+ case 'h':
+ val = buffer[2] >> 2;
+ break;
+
+ 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. */
+
+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];
+
+ word = NEXTWORD (p);
+
+ /* 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:
+ base_disp = NEXTWORD (p);
+ break;
+ case 3:
+ base_disp = NEXTLONG (p);
+ }
+ 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:
+ outer_disp = NEXTWORD (p);
+ break;
+ case 3:
+ outer_disp = NEXTLONG (p);
+ }
+
+ 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;
+}
+
+/* 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.
+ 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" };
+ val = fetch_arg (buffer, place, 2, info);
+ (*info->fprintf_func) (info->stream, cacheFieldName[val]);
+ break;
+ }
+
+ case 'a': /* Address register indirect only. Cf. case '+'. */
+ {
+ (*info->fprintf_func)
+ (info->stream,
+ "%s@",
+ reg_names[fetch_arg (buffer, place, 3, info) + 8]);
+ break;
+ }
+
+ case '_': /* 32-bit absolute address for move16. */
+ {
+ uval = NEXTULONG (p);
+ (*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. This table can't get it right
+ because it doesn't know which processor it's disassembling for. */
+ static const struct { char *name; int value; } names[]
+ = {{"%sfc", 0x000}, {"%dfc", 0x001}, {"%cacr", 0x002},
+ {"%tc", 0x003}, {"%itt0",0x004}, {"%itt1", 0x005},
+ {"%dtt0",0x006}, {"%dtt1",0x007}, {"%buscr",0x008},
+ {"%usp", 0x800}, {"%vbr", 0x801}, {"%caar", 0x802},
+ {"%msp", 0x803}, {"%isp", 0x804},
+ /* reg c04 is sometimes called flashbar or rambar.
+ rec c05 is also sometimes called rambar. */
+ {"%rambar0", 0xc04}, {"%rambar1", 0xc05},
+
+ /* 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}};
+
+ val = fetch_arg (buffer, place, 12, info);
+ for (regno = sizeof names / sizeof names[0] - 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, "%d", val);
+ }
+ break;
+
+ case 'Q':
+ val = fetch_arg (buffer, place, 3, info);
+ /* 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':
+ val = fetch_arg (buffer, place, 3, info);
+ /* 0 means -1. */
+ if (val == 0)
+ val = -1;
+ (*info->fprintf_func) (info->stream, "#%d", val);
+ break;
+
+ case 'j':
+ val = fetch_arg (buffer, place, 3, info);
+ (*info->fprintf_func) (info->stream, "#%d", val+1);
+ break;
+
+ case 'K':
+ val = fetch_arg (buffer, place, 9, info);
+ (*info->fprintf_func) (info->stream, "#%d", val);
+ break;
+
+ case 'M':
+ if (place == 'h')
+ {
+ static char *const scalefactor_name[] = { "<<", ">>" };
+ val = fetch_arg (buffer, place, 1, info);
+ (*info->fprintf_func) (info->stream, scalefactor_name[val]);
+ }
+ else
+ {
+ val = fetch_arg (buffer, place, 8, info);
+ if (val & 0x80)
+ val = val - 0x100;
+ (*info->fprintf_func) (info->stream, "#%d", val);
+ }
+ break;
+
+ case 'T':
+ val = fetch_arg (buffer, place, 4, info);
+ (*info->fprintf_func) (info->stream, "#%d", val);
+ break;
+
+ case 'D':
+ (*info->fprintf_func) (info->stream, "%s",
+ reg_names[fetch_arg (buffer, place, 3, info)]);
+ break;
+
+ case 'A':
+ (*info->fprintf_func)
+ (info->stream, "%s",
+ reg_names[fetch_arg (buffer, place, 3, info) + 010]);
+ break;
+
+ case 'R':
+ (*info->fprintf_func)
+ (info->stream, "%s",
+ reg_names[fetch_arg (buffer, place, 4, info)]);
+ break;
+
+ case 'r':
+ regno = fetch_arg (buffer, place, 4, info);
+ 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':
+ (*info->fprintf_func)
+ (info->stream, "%%fp%d",
+ fetch_arg (buffer, place, 3, info));
+ break;
+
+ case 'O':
+ val = fetch_arg (buffer, place, 6, info);
+ if (val & 0x20)
+ (*info->fprintf_func) (info->stream, "%s", reg_names[val & 7]);
+ else
+ (*info->fprintf_func) (info->stream, "%d", val);
+ break;
+
+ case '+':
+ (*info->fprintf_func)
+ (info->stream, "%s@+",
+ reg_names[fetch_arg (buffer, place, 3, info) + 8]);
+ break;
+
+ case '-':
+ (*info->fprintf_func)
+ (info->stream, "%s@-",
+ reg_names[fetch_arg (buffer, place, 3, info) + 8]);
+ break;
+
+ case 'k':
+ if (place == 'k')
+ (*info->fprintf_func)
+ (info->stream, "{%s}",
+ reg_names[fetch_arg (buffer, place, 3, info)]);
+ else if (place == 'C')
+ {
+ val = fetch_arg (buffer, place, 7, info);
+ if (val > 63) /* This is a signed constant. */
+ val -= 128;
+ (*info->fprintf_func) (info->stream, "{#%d}", val);
+ }
+ else
+ return -2;
+ break;
+
+ case '#':
+ case '^':
+ p1 = buffer + (*d == '#' ? 2 : 4);
+ if (place == 's')
+ val = fetch_arg (buffer, place, 4, info);
+ else if (place == 'C')
+ val = fetch_arg (buffer, place, 7, info);