aboutsummaryrefslogtreecommitdiff
path: root/opcodes/cris-dis.c
diff options
context:
space:
mode:
Diffstat (limited to 'opcodes/cris-dis.c')
-rw-r--r--opcodes/cris-dis.c494
1 files changed, 417 insertions, 77 deletions
diff --git a/opcodes/cris-dis.c b/opcodes/cris-dis.c
index 6beb4ab..372f085 100644
--- a/opcodes/cris-dis.c
+++ b/opcodes/cris-dis.c
@@ -62,9 +62,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
FIXME: Make this optional later. */
#ifndef TRACE_CASE
-#define TRACE_CASE 1
+#define TRACE_CASE (disdata->trace_case)
#endif
+enum cris_disass_family
+ { cris_dis_v0_v10, cris_dis_common_v10_v32, cris_dis_v32 };
+
+/* Stored in the disasm_info->private_data member. */
+struct cris_disasm_data
+{
+ /* Whether to print something less confusing if we find something
+ matching a switch-construct. */
+ bfd_boolean trace_case;
+
+ /* Whether this code is flagged as crisv32. FIXME: Should be an enum
+ that includes "compatible". */
+ enum cris_disass_family distype;
+};
+
/* Value of first element in switch. */
static long case_offset = 0;
@@ -80,45 +95,99 @@ static long last_immediate = 0;
static int number_of_bits
PARAMS ((unsigned int));
static char *format_hex
- PARAMS ((unsigned long, char *));
+ PARAMS ((unsigned long, char *, struct cris_disasm_data *));
static char *format_dec
PARAMS ((long, char *, int));
static char *format_reg
- PARAMS ((int, char *, bfd_boolean));
+ PARAMS ((struct cris_disasm_data *, int, char *, bfd_boolean));
+static char *format_sup_reg
+ PARAMS ((unsigned int, char *, bfd_boolean));
static int cris_constraint
- PARAMS ((const char *, unsigned int, unsigned int));
+ PARAMS ((const char *, unsigned int, unsigned int,
+ struct cris_disasm_data *));
static unsigned bytes_to_skip
- PARAMS ((unsigned int, const struct cris_opcode *));
+ PARAMS ((unsigned int, const struct cris_opcode *,
+ enum cris_disass_family));
static char *print_flags
- PARAMS ((unsigned int, char *));
+ PARAMS ((struct cris_disasm_data *, unsigned int, char *));
static void print_with_operands
PARAMS ((const struct cris_opcode *, unsigned int, unsigned char *,
bfd_vma, disassemble_info *, const struct cris_opcode *,
unsigned int, unsigned char *, bfd_boolean));
static const struct cris_spec_reg *spec_reg_info
- PARAMS ((unsigned int));
+ PARAMS ((unsigned int, enum cris_disass_family));
static int print_insn_cris_generic
PARAMS ((bfd_vma, disassemble_info *, bfd_boolean));
static int print_insn_cris_with_register_prefix
PARAMS ((bfd_vma, disassemble_info *));
static int print_insn_cris_without_register_prefix
PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_crisv32_with_register_prefix
+ PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_crisv32_without_register_prefix
+ PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_crisv10_v32_with_register_prefix
+ PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_crisv10_v32_without_register_prefix
+ PARAMS ((bfd_vma, disassemble_info *));
+static bfd_boolean cris_parse_disassembler_options
+ PARAMS ((disassemble_info *, enum cris_disass_family));
static const struct cris_opcode *get_opcode_entry
- PARAMS ((unsigned int, unsigned int));
+ PARAMS ((unsigned int, unsigned int, struct cris_disasm_data *));
+
+/* Parse disassembler options and store state in info. FIXME: For the
+ time being, we abuse static variables. */
+
+static bfd_boolean
+cris_parse_disassembler_options (info, distype)
+ disassemble_info *info;
+ enum cris_disass_family distype;
+{
+ struct cris_disasm_data *disdata;
+
+ info->private_data = calloc (1, sizeof (struct cris_disasm_data));
+ disdata = (struct cris_disasm_data *) info->private_data;
+ if (disdata == NULL)
+ return FALSE;
+
+ /* Default true. */
+ disdata->trace_case
+ = (info->disassembler_options == NULL
+ || (strcmp (info->disassembler_options, "nocase") != 0));
+
+ disdata->distype = distype;
+ return TRUE;
+}
-/* Return the descriptor of a special register.
- FIXME: Depend on a CPU-version specific argument when all machinery
- is in place. */
static const struct cris_spec_reg *
-spec_reg_info (sreg)
+spec_reg_info (sreg, distype)
unsigned int sreg;
+ enum cris_disass_family distype;
{
int i;
for (i = 0; cris_spec_regs[i].name != NULL; i++)
{
if (cris_spec_regs[i].number == sreg)
- return &cris_spec_regs[i];
+ {
+ if (distype == cris_dis_v32)
+ switch (cris_spec_regs[i].applicable_version)
+ {
+ case cris_ver_warning:
+ case cris_ver_version_all:
+ case cris_ver_v3p:
+ case cris_ver_v8p:
+ case cris_ver_v10p:
+ case cris_ver_v32p:
+ /* No ambiguous sizes or register names with CRISv32. */
+ if (cris_spec_regs[i].warning == NULL)
+ return &cris_spec_regs[i];
+ default:
+ ;
+ }
+ else if (cris_spec_regs[i].applicable_version != cris_ver_v32p)
+ return &cris_spec_regs[i];
+ }
}
return NULL;
@@ -141,9 +210,10 @@ number_of_bits (val)
/* Get an entry in the opcode-table. */
static const struct cris_opcode *
-get_opcode_entry (insn, prefix_insn)
+get_opcode_entry (insn, prefix_insn, disdata)
unsigned int insn;
unsigned int prefix_insn;
+ struct cris_disasm_data *disdata;
{
/* For non-prefixed insns, we keep a table of pointers, indexed by the
insn code. Each entry is initialized when found to be NULL. */
@@ -162,27 +232,45 @@ get_opcode_entry (insn, prefix_insn)
/* Allocate and clear the opcode-table. */
if (opc_table == NULL)
{
- opc_table = xmalloc (65536 * sizeof (opc_table[0]));
+ opc_table = malloc (65536 * sizeof (opc_table[0]));
+ if (opc_table == NULL)
+ return NULL;
+
memset (opc_table, 0, 65536 * sizeof (const struct cris_opcode *));
dip_prefixes
- = xmalloc (65536 * sizeof (const struct cris_opcode **));
+ = malloc (65536 * sizeof (const struct cris_opcode **));
+ if (dip_prefixes == NULL)
+ return NULL;
+
memset (dip_prefixes, 0, 65536 * sizeof (dip_prefixes[0]));
bdapq_m1_prefixes
- = xmalloc (65536 * sizeof (const struct cris_opcode **));
+ = malloc (65536 * sizeof (const struct cris_opcode **));
+ if (bdapq_m1_prefixes == NULL)
+ return NULL;
+
memset (bdapq_m1_prefixes, 0, 65536 * sizeof (bdapq_m1_prefixes[0]));
bdapq_m2_prefixes
- = xmalloc (65536 * sizeof (const struct cris_opcode **));
+ = malloc (65536 * sizeof (const struct cris_opcode **));
+ if (bdapq_m2_prefixes == NULL)
+ return NULL;
+
memset (bdapq_m2_prefixes, 0, 65536 * sizeof (bdapq_m2_prefixes[0]));
bdapq_m4_prefixes
- = xmalloc (65536 * sizeof (const struct cris_opcode **));
+ = malloc (65536 * sizeof (const struct cris_opcode **));
+ if (bdapq_m4_prefixes == NULL)
+ return NULL;
+
memset (bdapq_m4_prefixes, 0, 65536 * sizeof (bdapq_m4_prefixes[0]));
rest_prefixes
- = xmalloc (65536 * sizeof (const struct cris_opcode **));
+ = malloc (65536 * sizeof (const struct cris_opcode **));
+ if (rest_prefixes == NULL)
+ return NULL;
+
memset (rest_prefixes, 0, 65536 * sizeof (rest_prefixes[0]));
}
@@ -197,7 +285,7 @@ get_opcode_entry (insn, prefix_insn)
const struct cris_opcode *popcodep
= (opc_table[prefix_insn] != NULL
? opc_table[prefix_insn]
- : get_opcode_entry (prefix_insn, NO_CRIS_PREFIX));
+ : get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata));
if (popcodep == NULL)
return NULL;
@@ -254,6 +342,60 @@ get_opcode_entry (insn, prefix_insn)
{
int level_of_match;
+ if (disdata->distype == cris_dis_v32)
+ {
+ switch (opcodep->applicable_version)
+ {
+ case cris_ver_version_all:
+ break;
+
+ case cris_ver_v0_3:
+ case cris_ver_v0_10:
+ case cris_ver_v3_10:
+ case cris_ver_sim_v0_10:
+ case cris_ver_v8_10:
+ case cris_ver_v10:
+ case cris_ver_warning:
+ continue;
+
+ case cris_ver_v3p:
+ case cris_ver_v8p:
+ case cris_ver_v10p:
+ case cris_ver_v32p:
+ break;
+
+ case cris_ver_v8:
+ abort ();
+ default:
+ abort ();
+ }
+ }
+ else
+ {
+ switch (opcodep->applicable_version)
+ {
+ case cris_ver_version_all:
+ case cris_ver_v0_3:
+ case cris_ver_v3p:
+ case cris_ver_v0_10:
+ case cris_ver_v8p:
+ case cris_ver_v8_10:
+ case cris_ver_v10:
+ case cris_ver_sim_v0_10:
+ case cris_ver_v10p:
+ case cris_ver_warning:
+ break;
+
+ case cris_ver_v32p:
+ continue;
+
+ case cris_ver_v8:
+ abort ();
+ default:
+ abort ();
+ }
+ }
+
/* We give a double lead for bits matching the template in
cris_opcodes. Not even, because then "move p8,r10" would
be given 2 bits lead over "clear.d r10". When there's a
@@ -265,7 +407,8 @@ get_opcode_entry (insn, prefix_insn)
&& ((level_of_match
= cris_constraint (opcodep->args,
insn,
- prefix_insn))
+ prefix_insn,
+ disdata))
>= 0)
&& ((level_of_match
+= 2 * number_of_bits (opcodep->match
@@ -300,9 +443,10 @@ get_opcode_entry (insn, prefix_insn)
/* Format number as hex with a leading "0x" into outbuffer. */
static char *
-format_hex (number, outbuffer)
+format_hex (number, outbuffer, disdata)
unsigned long number;
char *outbuffer;
+ struct cris_disasm_data *disdata;
{
/* Obfuscate to avoid warning on 32-bit host, but properly truncate
negative numbers on >32-bit hosts. */
@@ -337,7 +481,8 @@ format_dec (number, outbuffer, signedp)
/* Format the name of the general register regno into outbuffer. */
static char *
-format_reg (regno, outbuffer_start, with_reg_prefix)
+format_reg (disdata, regno, outbuffer_start, with_reg_prefix)
+ struct cris_disasm_data *disdata;
int regno;
char *outbuffer_start;
bfd_boolean with_reg_prefix;
@@ -350,7 +495,11 @@ format_reg (regno, outbuffer_start, with_reg_prefix)
switch (regno)
{
case 15:
- strcpy (outbuffer, "pc");
+ /* For v32, there is no context in which we output PC. */
+ if (disdata->distype == cris_dis_v32)
+ strcpy (outbuffer, "acr");
+ else
+ strcpy (outbuffer, "pc");
break;
case 14:
@@ -365,15 +514,43 @@ format_reg (regno, outbuffer_start, with_reg_prefix)
return outbuffer_start + strlen (outbuffer_start);
}
+/* Format the name of a support register into outbuffer. */
+
+static char *
+format_sup_reg (regno, outbuffer_start, with_reg_prefix)
+ unsigned int regno;
+ char *outbuffer_start;
+ bfd_boolean with_reg_prefix;
+{
+ char *outbuffer = outbuffer_start;
+ int i;
+
+ if (with_reg_prefix)
+ *outbuffer++ = REGISTER_PREFIX_CHAR;
+
+ for (i = 0; cris_support_regs[i].name != NULL; i++)
+ if (cris_support_regs[i].number == regno)
+ {
+ sprintf (outbuffer, "%s", cris_support_regs[i].name);
+ return outbuffer_start + strlen (outbuffer_start);
+ }
+
+ /* There's supposed to be register names covering all numbers, though
+ some may be generic names. */
+ sprintf (outbuffer, "format_sup_reg-BUG");
+ return outbuffer_start + strlen (outbuffer_start);
+}
+
/* Return -1 if the constraints of a bitwise-matched instruction say
that there is no match. Otherwise return a nonnegative number
indicating the confidence in the match (higher is better). */
static int
-cris_constraint (cs, insn, prefix_insn)
+cris_constraint (cs, insn, prefix_insn, disdata)
const char *cs;
unsigned int insn;
unsigned int prefix_insn;
+ struct cris_disasm_data *disdata;
{
int retval = 0;
int tmp;
@@ -384,11 +561,17 @@ cris_constraint (cs, insn, prefix_insn)
switch (*s)
{
case '!':
- /* Do not recognize "pop" if there's a prefix. */
- if (prefix_insn != NO_CRIS_PREFIX)
+ /* Do not recognize "pop" if there's a prefix and then only for
+ v0..v10. */
+ if (prefix_insn != NO_CRIS_PREFIX
+ || disdata->distype != cris_dis_v0_v10)
return -1;
break;
+ case 'U':
+ /* Not recognized at disassembly. */
+ return -1;
+
case 'M':
/* Size modifier for "clear", i.e. special register 0, 4 or 8.
Check that it is one of them. Only special register 12 could
@@ -416,6 +599,7 @@ cris_constraint (cs, insn, prefix_insn)
case 's':
case 'y':
+ case 'Y':
/* If this is a prefixed insn with postincrement (side-effect),
the prefix must not be DIP. */
if (prefix_insn != NO_CRIS_PREFIX)
@@ -423,7 +607,7 @@ cris_constraint (cs, insn, prefix_insn)
if (insn & 0x400)
{
const struct cris_opcode *prefix_opcodep
- = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX);
+ = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata);
if (prefix_opcodep->match == DIP_OPCODE)
return -1;
@@ -443,7 +627,7 @@ cris_constraint (cs, insn, prefix_insn)
{
/* Match the prefix insn to BDAPQ. */
const struct cris_opcode *prefix_opcodep
- = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX);
+ = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata);
if (prefix_opcodep->match == BDAP_QUICK_OPCODE)
{
@@ -456,7 +640,7 @@ cris_constraint (cs, insn, prefix_insn)
{
unsigned int spec_reg = (insn >> 12) & 15;
const struct cris_spec_reg *sregp
- = spec_reg_info (spec_reg);
+ = spec_reg_info (spec_reg, disdata->distype);
/* For a special-register, the "prefix size" must
match the size of the register. */
@@ -485,7 +669,7 @@ cris_constraint (cs, insn, prefix_insn)
case 'P':
{
const struct cris_spec_reg *sregp
- = spec_reg_info ((insn >> 12) & 15);
+ = spec_reg_info ((insn >> 12) & 15, disdata->distype);
/* Since we match four bits, we will give a value of 4-1 = 3
in a match. If there is a corresponding exact match of a
@@ -518,9 +702,10 @@ cris_constraint (cs, insn, prefix_insn)
/* Return the length of an instruction. */
static unsigned
-bytes_to_skip (insn, matchedp)
+bytes_to_skip (insn, matchedp, distype)
unsigned int insn;
const struct cris_opcode *matchedp;
+ enum cris_disass_family distype;
{
/* Each insn is a word plus "immediate" operands. */
unsigned to_skip = 2;
@@ -528,7 +713,8 @@ bytes_to_skip (insn, matchedp)
const char *s;
for (s = template; *s; s++)
- if (*s == 's' && (insn & 0x400) && (insn & 15) == 15)
+ if ((*s == 's' || *s == 'N' || *s == 'Y')
+ && (insn & 0x400) && (insn & 15) == 15)
{
/* Immediate via [pc+], so we have to check the size of the
operand. */
@@ -539,19 +725,24 @@ bytes_to_skip (insn, matchedp)
else if (matchedp->imm_oprnd_size == SIZE_SPEC_REG)
{
const struct cris_spec_reg *sregp
- = spec_reg_info ((insn >> 12) & 15);
+ = spec_reg_info ((insn >> 12) & 15, distype);
/* FIXME: Improve error handling; should have been caught
earlier. */
if (sregp == NULL)
return 2;
- /* PC is incremented by two, not one, for a byte. */
- to_skip += (sregp->reg_size + 1) & ~1;
+ /* PC is incremented by two, not one, for a byte. Except on
+ CRISv32, where constants are always DWORD-size for
+ special registers. */
+ to_skip +=
+ distype == cris_dis_v32 ? 4 : (sregp->reg_size + 1) & ~1;
}
else
to_skip += (mode_size + 1) & ~1;
}
+ else if (*s == 'n')
+ to_skip += 4;
else if (*s == 'b')
to_skip += 2;
@@ -561,15 +752,20 @@ bytes_to_skip (insn, matchedp)
/* Print condition code flags. */
static char *
-print_flags (insn, cp)
+print_flags (disdata, insn, cp)
+ struct cris_disasm_data *disdata;
unsigned int insn;
char *cp;
{
/* Use the v8 (Etrax 100) flag definitions for disassembly.
The differences with v0 (Etrax 1..4) vs. Svinto are:
- v0 'd' <=> v8 'm'
- v0 'e' <=> v8 'b'. */
- static const char fnames[] = "cvznxibm";
+ v0 'd' <=> v8 'm'
+ v0 'e' <=> v8 'b'.
+ FIXME: Emit v0..v3 flag names somehow. */
+ static const char v8_fnames[] = "cvznxibm";
+ static const char v32_fnames[] = "cvznxiup";
+ const char *fnames
+ = disdata->distype == cris_dis_v32 ? v32_fnames : v8_fnames;
unsigned char flagbits = (((insn >> 8) & 0xf0) | (insn & 15));
int i;
@@ -608,6 +804,8 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
static const char mode_char[] = "bwd?";
const char *s;
const char *cs;
+ struct cris_disasm_data *disdata
+ = (struct cris_disasm_data *) info->private_data;
/* Print out the name first thing we do. */
(*info->fprintf_func) (info->stream, "%s", opcodep->name);
@@ -658,14 +856,33 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
{
switch (*s)
{
+ case 'T':
+ tp = format_sup_reg ((insn >> 12) & 15, tp, with_reg_prefix);
+ break;
+
+ case 'A':
+ if (with_reg_prefix)
+ *tp++ = REGISTER_PREFIX_CHAR;
+ *tp++ = 'a';
+ *tp++ = 'c';
+ *tp++ = 'r';
+ break;
+
+ case '[':
+ case ']':
case ',':
*tp++ = *s;
break;
case '!':
- /* Ignore at this point; used at earlier stages to avoid recognition
- if there's a prefixes at something that in other ways looks like
- a "pop". */
+ /* Ignore at this point; used at earlier stages to avoid
+ recognition if there's a prefix at something that in other
+ ways looks like a "pop". */
+ break;
+
+ case 'd':
+ /* Ignore. This is an optional ".d " on the large one of
+ relaxable insns. */
break;
case 'B':
@@ -677,14 +894,48 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
case 'D':
case 'r':
- tp = format_reg (insn & 15, tp, with_reg_prefix);
+ tp = format_reg (disdata, insn & 15, tp, with_reg_prefix);
break;
case 'R':
- tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix);
+ tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
+ break;
+
+ case 'n':
+ {
+ /* Like N but pc-relative to the start of the insn. */
+ unsigned long number
+ = (buffer[2] + buffer[3] * 256 + buffer[4] * 65536
+ + buffer[5] * 0x1000000 + addr);
+
+ /* Finish off and output previous formatted bytes. */
+ *tp = 0;
+ if (temp[0])
+ (*info->fprintf_func) (info->stream, "%s", temp);
+ tp = temp;
+
+ (*info->print_address_func) ((bfd_vma) number, info);
+ }
+ break;
+
+ case 'u':
+ {
+ /* Like n but the offset is bits <3:0> in the instruction. */
+ unsigned long number = (buffer[0] & 0xf) * 2 + addr;
+
+ /* Finish off and output previous formatted bytes. */
+ *tp = 0;
+ if (temp[0])
+ (*info->fprintf_func) (info->stream, "%s", temp);
+ tp = temp;
+
+ (*info->print_address_func) ((bfd_vma) number, info);
+ }
break;
+ case 'N':
case 'y':
+ case 'Y':
case 'S':
case 's':
/* Any "normal" memory operand. */
@@ -703,7 +954,7 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG)
{
const struct cris_spec_reg *sregp
- = spec_reg_info ((insn >> 12) & 15);
+ = spec_reg_info ((insn >> 12) & 15, disdata->distype);
/* A NULL return should have been as a non-match earlier,
so catch it as an internal error in the error-case
@@ -712,8 +963,11 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
/* Whatever non-valid size. */
nbytes = 42;
else
- /* PC is always incremented by a multiple of two. */
- nbytes = (sregp->reg_size + 1) & ~1;
+ /* PC is always incremented by a multiple of two.
+ For CRISv32, immediates are always 4 bytes for
+ special registers. */
+ nbytes = disdata->distype == cris_dis_v32
+ ? 4 : (sregp->reg_size + 1) & ~1;
}
else
{
@@ -781,7 +1035,7 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
info->target = number;
}
else
- tp = format_hex (number, tp);
+ tp = format_hex (number, tp, disdata);
}
}
else
@@ -802,7 +1056,7 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG)
{
const struct cris_spec_reg *sregp
- = spec_reg_info ((insn >> 12) & 15);
+ = spec_reg_info ((insn >> 12) & 15, disdata->distype);
/* FIXME: Improve error handling; should have been caught
earlier. */
@@ -827,7 +1081,7 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
{
if (insn & 0x400)
{
- tp = format_reg (insn & 15, tp, with_reg_prefix);
+ tp = format_reg (disdata, insn & 15, tp, with_reg_prefix);
*tp++ = '=';
}
@@ -869,7 +1123,7 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
info->target2 = prefix_insn & 15;
*tp++ = '[';
- tp = format_reg (prefix_insn & 15, tp,
+ tp = format_reg (disdata, prefix_insn & 15, tp,
with_reg_prefix);
if (prefix_insn & 0x400)
*tp++ = '+';
@@ -886,7 +1140,7 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
number -= 256;
/* Output "reg+num" or, if num < 0, "reg-num". */
- tp = format_reg ((prefix_insn >> 12) & 15, tp,
+ tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp,
with_reg_prefix);
if (number >= 0)
*tp++ = '+';
@@ -900,9 +1154,10 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
case BIAP_OPCODE:
/* Output "r+R.m". */
- tp = format_reg (prefix_insn & 15, tp, with_reg_prefix);
+ tp = format_reg (disdata, prefix_insn & 15, tp,
+ with_reg_prefix);
*tp++ = '+';
- tp = format_reg ((prefix_insn >> 12) & 15, tp,
+ tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp,
with_reg_prefix);
*tp++ = '.';
*tp++ = mode_char[(prefix_insn >> 4) & 3];
@@ -925,7 +1180,7 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
case BDAP_INDIR_OPCODE:
/* Output "r+s.m", or, if "s" is [pc+], "r+s" or
"r-s". */
- tp = format_reg ((prefix_insn >> 12) & 15, tp,
+ tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp,
with_reg_prefix);
if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15)
@@ -996,7 +1251,7 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
/* Output "r+[R].m" or "r+[R+].m". */
*tp++ = '+';
*tp++ = '[';
- tp = format_reg (prefix_insn & 15, tp,
+ tp = format_reg (disdata, prefix_insn & 15, tp,
with_reg_prefix);
if (prefix_insn & 0x400)
*tp++ = '+';
@@ -1026,7 +1281,7 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
}
else
{
- tp = format_reg (insn & 15, tp, with_reg_prefix);
+ tp = format_reg (disdata, insn & 15, tp, with_reg_prefix);
info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;
info->target = insn & 15;
@@ -1039,7 +1294,7 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
break;
case 'x':
- tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix);
+ tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
*tp++ = '.';
*tp++ = mode_char[(insn >> 4) & 3];
break;
@@ -1055,7 +1310,7 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
if (where > 32767)
where -= 65536;
- where += addr + 4;
+ where += addr + ((disdata->distype == cris_dis_v32) ? 0 : 4);
if (insn == BA_PC_INCR_OPCODE)
info->insn_type = dis_branch;
@@ -1084,6 +1339,7 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
case 'o':
{
long offset = insn & 0xfe;
+ bfd_vma target;
if (insn & 1)
offset |= ~0xff;
@@ -1093,15 +1349,16 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
else
info->insn_type = dis_condbranch;
- info->target = (bfd_vma) (addr + 2 + offset);
+ target = addr + ((disdata->distype == cris_dis_v32) ? 0 : 2) + offset;
+ info->target = target;
*tp = 0;
tp = temp;
(*info->fprintf_func) (info->stream, "%s", temp);
-
- (*info->print_address_func) ((bfd_vma) (addr + 2 + offset), info);
+ (*info->print_address_func) (target, info);
}
break;
+ case 'Q':
case 'O':
{
long number = buffer[0];
@@ -1111,12 +1368,12 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
tp = format_dec (number, tp, 1);
*tp++ = ',';
- tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix);
+ tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
}
break;
case 'f':
- tp = print_flags (insn, tp);
+ tp = print_flags (disdata, insn, tp);
break;
case 'i':
@@ -1126,7 +1383,7 @@ print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
case 'P':
{
const struct cris_spec_reg *sregp
- = spec_reg_info ((insn >> 12) & 15);
+ = spec_reg_info ((insn >> 12) & 15, disdata->distype);
if (sregp->name == NULL)
/* Should have been caught as a non-match eariler. */
@@ -1198,6 +1455,8 @@ print_insn_cris_generic (memaddr, info, with_reg_prefix)
unsigned int insn;
const struct cris_opcode *matchedp;
int advance = 0;
+ struct cris_disasm_data *disdata
+ = (struct cris_disasm_data *) info->private_data;
/* No instruction will be disassembled as longer than this number of
bytes; stacked prefixes will not be expanded. */
@@ -1276,7 +1535,9 @@ print_insn_cris_generic (memaddr, info, with_reg_prefix)
valid "bcc .+2" insn, it is also useless enough and enough
of a nuiscance that we will just output "bcc .+2" for it
and signal it as a noninsn. */
- (*info->fprintf_func) (info->stream, "bcc .+2");
+ (*info->fprintf_func) (info->stream,
+ disdata->distype == cris_dis_v32
+ ? "bcc ." : "bcc .+2");
info->insn_type = dis_noninsn;
advance += 2;
}
@@ -1287,7 +1548,7 @@ print_insn_cris_generic (memaddr, info, with_reg_prefix)
unsigned int prefix_insn = insn;
int prefix_size = 0;
- matchedp = get_opcode_entry (insn, NO_CRIS_PREFIX);
+ matchedp = get_opcode_entry (insn, NO_CRIS_PREFIX, disdata);
/* Check if we're supposed to write out prefixes as address
modes and if this was a prefix. */
@@ -1295,11 +1556,12 @@ print_insn_cris_generic (memaddr, info, with_reg_prefix)
{
/* If it's a prefix, put it into the prefix vars and get the
main insn. */
- prefix_size = bytes_to_skip (prefix_insn, matchedp);
+ prefix_size = bytes_to_skip (prefix_insn, matchedp,
+ disdata->distype);
prefix_opcodep = matchedp;
insn = bufp[prefix_size] + bufp[prefix_size + 1] * 256;
- matchedp = get_opcode_entry (insn, prefix_insn);
+ matchedp = get_opcode_entry (insn, prefix_insn, disdata);
if (matchedp != NULL)
{
@@ -1327,7 +1589,7 @@ print_insn_cris_generic (memaddr, info, with_reg_prefix)
}
else
{
- advance += bytes_to_skip (insn, matchedp);
+ advance += bytes_to_skip (insn, matchedp, disdata->distype);
/* The info_type and assorted fields will be set according
to the operands. */
@@ -1368,28 +1630,90 @@ print_insn_cris_generic (memaddr, info, with_reg_prefix)
return advance;
}
-/* Disassemble, prefixing register names with `$'. */
+/* Disassemble, prefixing register names with `$'. CRIS v0..v10. */
static int
print_insn_cris_with_register_prefix (vma, info)
bfd_vma vma;
disassemble_info *info;
{
+ if (info->private_data == NULL
+ && !cris_parse_disassembler_options (info, cris_dis_v0_v10))
+ return -1;
+ return print_insn_cris_generic (vma, info, TRUE);
+}
+
+/* Disassemble, prefixing register names with `$'. CRIS v32. */
+
+static int
+print_insn_crisv32_with_register_prefix (vma, info)
+ bfd_vma vma;
+ disassemble_info *info;
+{
+ if (info->private_data == NULL
+ && !cris_parse_disassembler_options (info, cris_dis_v32))
+ return -1;
+ return print_insn_cris_generic (vma, info, TRUE);
+}
+
+/* Disassemble, prefixing register names with `$'.
+ Common v10 and v32 subset. */
+
+static int
+print_insn_crisv10_v32_with_register_prefix (vma, info)
+ bfd_vma vma;
+ disassemble_info *info;
+{
+ if (info->private_data == NULL
+ && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32))
+ return -1;
return print_insn_cris_generic (vma, info, TRUE);
}
-/* Disassemble, no prefixes on register names. */
+/* Disassemble, no prefixes on register names. CRIS v0..v10. */
static int
print_insn_cris_without_register_prefix (vma, info)
bfd_vma vma;
disassemble_info *info;
{
+ if (info->private_data == NULL
+ && !cris_parse_disassembler_options (info, cris_dis_v0_v10))
+ return -1;
+ return print_insn_cris_generic (vma, info, FALSE);
+}
+
+/* Disassemble, no prefixes on register names. CRIS v32. */
+
+static int
+print_insn_crisv32_without_register_prefix (vma, info)
+ bfd_vma vma;
+ disassemble_info *info;
+{
+ if (info->private_data == NULL
+ && !cris_parse_disassembler_options (info, cris_dis_v32))
+ return -1;
+ return print_insn_cris_generic (vma, info, FALSE);
+}
+
+/* Disassemble, no prefixes on register names.
+ Common v10 and v32 subset. */
+
+static int
+print_insn_crisv10_v32_without_register_prefix (vma, info)
+ bfd_vma vma;
+ disassemble_info *info;
+{
+ if (info->private_data == NULL
+ && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32))
+ return -1;
return print_insn_cris_generic (vma, info, FALSE);
}
/* Return a disassembler-function that prints registers with a `$' prefix,
- or one that prints registers without a prefix. */
+ or one that prints registers without a prefix.
+ FIXME: We should improve the solution to avoid the multitude of
+ functions seen above. */
disassembler_ftype
cris_get_disassembler (abfd)
@@ -1397,10 +1721,26 @@ cris_get_disassembler (abfd)
{
/* If there's no bfd in sight, we return what is valid as input in all
contexts if fed back to the assembler: disassembly *with* register
- prefix. */
- if (abfd == NULL || bfd_get_symbol_leading_char (abfd) == 0)
+ prefix. Unfortunately this will be totally wrong for v32. */
+ if (abfd == NULL)
return print_insn_cris_with_register_prefix;
+ if (bfd_get_symbol_leading_char (abfd) == 0)
+ {
+ if (bfd_get_mach (abfd) == bfd_mach_cris_v32)
+ return print_insn_crisv32_with_register_prefix;
+ if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32)
+ return print_insn_crisv10_v32_with_register_prefix;
+
+ /* We default to v10. This may be specifically specified in the
+ bfd mach, but is also the default setting. */
+ return print_insn_cris_with_register_prefix;
+ }
+
+ if (bfd_get_mach (abfd) == bfd_mach_cris_v32)
+ return print_insn_crisv32_without_register_prefix;
+ if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32)
+ return print_insn_crisv10_v32_without_register_prefix;
return print_insn_cris_without_register_prefix;
}