#include "dis-asm.h"
#include "sysdep.h"
#include "opcode/cris.h"
#include "libiberty.h"
#define false 0
#define true 1
#ifndef MAX_BYTES_PER_CRIS_INSN
#define MAX_BYTES_PER_CRIS_INSN 8
#endif
#ifndef PARSE_PREFIX
#define PARSE_PREFIX 1
#endif
#define REGISTER_PREFIX_CHAR '$'
#ifndef TRACE_CASE
#define TRACE_CASE 1
#endif
static long case_offset = 0;
static long case_offset_counter = 0;
static long no_of_case_offsets = 0;
static long last_immediate = 0;
static int number_of_bits PARAMS ((unsigned int));
static char *format_hex PARAMS ((unsigned long, char *));
static char *format_dec PARAMS ((long, char *, int));
static char *format_reg PARAMS ((int, char *, boolean));
static int cris_constraint PARAMS ((const char *, unsigned int,
unsigned int));
static unsigned bytes_to_skip PARAMS ((unsigned int,
const struct cris_opcode *));
static char *print_flags PARAMS ((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 *, boolean));
static const struct cris_spec_reg *spec_reg_info PARAMS ((unsigned int));
static int print_insn_cris_generic
PARAMS ((bfd_vma, disassemble_info *, 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 const struct cris_opcode *get_opcode_entry
PARAMS ((unsigned int, unsigned int));
static const struct cris_spec_reg *
spec_reg_info (sreg)
unsigned int sreg;
{
int i;
for (i = 0; cris_spec_regs[i].name != NULL; i++)
{
if (cris_spec_regs[i].number == sreg)
return &cris_spec_regs[i];
}
return NULL;
}
static int
number_of_bits (val)
unsigned int val;
{
int bits;
for (bits = 0; val != 0; val &= val - 1)
bits++;
return bits;
}
static const struct cris_opcode *
get_opcode_entry (insn, prefix_insn)
unsigned int insn;
unsigned int prefix_insn;
{
static const struct cris_opcode **opc_table = NULL;
const struct cris_opcode *max_matchedp = NULL;
const struct cris_opcode **prefix_opc_table = NULL;
static const struct cris_opcode **dip_prefixes = NULL;
static const struct cris_opcode **bdapq_m1_prefixes = NULL;
static const struct cris_opcode **bdapq_m2_prefixes = NULL;
static const struct cris_opcode **bdapq_m4_prefixes = NULL;
static const struct cris_opcode **rest_prefixes = NULL;
if (opc_table == NULL)
{
opc_table = xmalloc (65536 * sizeof (opc_table[0]));
memset (opc_table, 0, 65536 * sizeof (const struct cris_opcode *));
dip_prefixes
= xmalloc (65536 * sizeof (const struct cris_opcode **));
memset (dip_prefixes, 0, 65536 * sizeof (dip_prefixes[0]));
bdapq_m1_prefixes
= xmalloc (65536 * sizeof (const struct cris_opcode **));
memset (bdapq_m1_prefixes, 0, 65536 * sizeof (bdapq_m1_prefixes[0]));
bdapq_m2_prefixes
= xmalloc (65536 * sizeof (const struct cris_opcode **));
memset (bdapq_m2_prefixes, 0, 65536 * sizeof (bdapq_m2_prefixes[0]));
bdapq_m4_prefixes
= xmalloc (65536 * sizeof (const struct cris_opcode **));
memset (bdapq_m4_prefixes, 0, 65536 * sizeof (bdapq_m4_prefixes[0]));
rest_prefixes
= xmalloc (65536 * sizeof (const struct cris_opcode **));
memset (rest_prefixes, 0, 65536 * sizeof (rest_prefixes[0]));
}
if (prefix_insn != NO_CRIS_PREFIX)
{
const struct cris_opcode *popcodep
= (opc_table[prefix_insn] != NULL
? opc_table[prefix_insn]
: get_opcode_entry (prefix_insn, NO_CRIS_PREFIX));
if (popcodep == NULL)
return NULL;
if (popcodep->match == BDAP_QUICK_OPCODE)
{
int offset = (prefix_insn & 255);
if (offset > 127)
offset -= 256;
switch (offset)
{
case -4:
prefix_opc_table = bdapq_m4_prefixes;
break;
case -2:
prefix_opc_table = bdapq_m2_prefixes;
break;
case -1:
prefix_opc_table = bdapq_m1_prefixes;
break;
default:
prefix_opc_table = rest_prefixes;
break;
}
}
else if (popcodep->match == DIP_OPCODE)
prefix_opc_table = dip_prefixes;
else
prefix_opc_table = rest_prefixes;
}
if (prefix_insn != NO_CRIS_PREFIX
&& prefix_opc_table[insn] != NULL)
max_matchedp = prefix_opc_table[insn];
else if (prefix_insn == NO_CRIS_PREFIX && opc_table[insn] != NULL)
max_matchedp = opc_table[insn];
else
{
const struct cris_opcode *opcodep;
int max_level_of_match = -1;
for (opcodep = cris_opcodes;
opcodep->name != NULL;
opcodep++)
{
int level_of_match;
if ((opcodep->match & insn) == opcodep->match
&& (opcodep->lose & insn) == 0
&& ((level_of_match
= cris_constraint (opcodep->args,
insn,
prefix_insn))
>= 0)
&& ((level_of_match
+= 2 * number_of_bits (opcodep->match
| opcodep->lose))
> max_level_of_match))
{
max_matchedp = opcodep;
max_level_of_match = level_of_match;
if (level_of_match >= 2 * 16)
break;
}
}
if (prefix_insn == NO_CRIS_PREFIX)
opc_table[insn] = max_matchedp;
else
prefix_opc_table[insn] = max_matchedp;
}
return max_matchedp;
}
static char *
format_hex (number, outbuffer)
unsigned long number;
char *outbuffer;
{
if (sizeof (number) > 4)
number &= (1 << (sizeof (number) > 4 ? 32 : 1)) - 1;
sprintf (outbuffer, "0x%lx", number);
if (TRACE_CASE)
last_immediate = number;
return outbuffer + strlen (outbuffer);
}
static char *
format_dec (number, outbuffer, signedp)
long number;
char *outbuffer;
int signedp;
{
last_immediate = number;
sprintf (outbuffer, signedp ? "%ld" : "%lu", number);
return outbuffer + strlen (outbuffer);
}
static char *
format_reg (regno, outbuffer_start, with_reg_prefix)
int regno;
char *outbuffer_start;
boolean with_reg_prefix;
{
char *outbuffer = outbuffer_start;
if (with_reg_prefix)
*outbuffer++ = REGISTER_PREFIX_CHAR;
switch (regno)
{
case 15:
strcpy (outbuffer, "pc");
break;
case 14:
strcpy (outbuffer, "sp");
break;
default:
sprintf (outbuffer, "r%d", regno);
break;
}
return outbuffer_start + strlen (outbuffer_start);
}
static int
cris_constraint (cs, insn, prefix_insn)
const char *cs;
unsigned int insn;
unsigned int prefix_insn;
{
int retval = 0;
int tmp;
int prefix_ok = 0;
const char *s;
for (s = cs; *s; s++)
switch (*s)
{
case '!':
if (prefix_insn != NO_CRIS_PREFIX)
return -1;
break;
case 'M':
tmp = ((insn >> 12) & 0xf);
if (tmp != 0 && tmp != 4 && tmp != 8)
return -1;
break;
case 'm':
if ((insn & 0x30) == 0x30)
return -1;
break;
case 'S':
if (prefix_insn != NO_CRIS_PREFIX && (insn & 0x400) == 0)
{
prefix_ok = 1;
break;
}
else
return -1;
case 's':
case 'y':
if (prefix_insn != NO_CRIS_PREFIX)
{
if (insn & 0x400)
{
const struct cris_opcode *prefix_opcodep
= get_opcode_entry (prefix_insn, NO_CRIS_PREFIX);
if (prefix_opcodep->match == DIP_OPCODE)
return -1;
}
prefix_ok = 1;
}
break;
case 'B':
prefix_ok = 1;
if (prefix_insn != NO_CRIS_PREFIX)
{
const struct cris_opcode *prefix_opcodep
= get_opcode_entry (prefix_insn, NO_CRIS_PREFIX);
if (prefix_opcodep->match == BDAP_QUICK_OPCODE)
{
int pushsize = (prefix_insn & 255);
if (pushsize > 127)
pushsize -= 256;
if (s[1] == 'P')
{
unsigned int spec_reg = (insn >> 12) & 15;
const struct cris_spec_reg *sregp
= spec_reg_info (spec_reg);
if (sregp && sregp->reg_size == (unsigned int) -pushsize)
break;
}
else if (s[1] == 'R')
{
if ((insn & 0x30) == 0x20 && pushsize == -4)
break;
}
}
}
return -1;
case 'D':
retval = (((insn >> 12) & 15) == (insn & 15));
if (!retval)
return -1;
else
retval += 4;
break;
case 'P':
{
const struct cris_spec_reg *sregp
= spec_reg_info ((insn >> 12) & 15);
if (sregp != NULL)
{
retval += 3;
break;
}
else
return -1;
}
}
if (prefix_insn != NO_CRIS_PREFIX && ! prefix_ok)
return -1;
return retval;
}
static unsigned
bytes_to_skip (insn, matchedp)
unsigned int insn;
const struct cris_opcode *matchedp;
{
unsigned to_skip = 2;
const char *template = matchedp->args;
const char *s;
for (s = template; *s; s++)
if (*s == 's' && (insn & 0x400) && (insn & 15) == 15)
{
int mode_size = 1 << ((insn >> 4) & (*template == 'z' ? 1 : 3));
if (matchedp->imm_oprnd_size == SIZE_FIX_32)
to_skip += 4;
else if (matchedp->imm_oprnd_size == SIZE_SPEC_REG)
{
const struct cris_spec_reg *sregp
= spec_reg_info ((insn >> 12) & 15);
if (sregp == NULL)
return 2;
to_skip += (sregp->reg_size + 1) & ~1;
}
else
to_skip += (mode_size + 1) & ~1;
}
else if (*s == 'b')
to_skip += 2;
return to_skip;
}
static char *
print_flags (insn, cp)
unsigned int insn;
char *cp;
{
static const char fnames[] = "cvznxibm";
unsigned char flagbits = (((insn >> 8) & 0xf0) | (insn & 15));
int i;
for (i = 0; i < 8; i++)
if (flagbits & (1 << i))
*cp++ = fnames[i];
return cp;
}
static void
print_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep,
prefix_insn, prefix_buffer, with_reg_prefix)
const struct cris_opcode *opcodep;
unsigned int insn;
unsigned char *buffer;
bfd_vma addr;
disassemble_info *info;
const struct cris_opcode *prefix_opcodep;
unsigned int prefix_insn;
unsigned char *prefix_buffer;
boolean with_reg_prefix;
{
char temp[sizeof (".d [$r13=$r12-2147483648],$r10") * 2];
char *tp = temp;
static const char mode_char[] = "bwd?";
const char *s;
const char *cs;
(*info->fprintf_func) (info->stream, "%s", opcodep->name);
cs = opcodep->args;
s = cs;
if (*s == 'p')
s++;
if (*s == 'm' || *s == 'M' || *s == 'z')
{
*tp++ = '.';
*tp++ = *s == 'M'
? (insn & 0x8000 ? 'd'
: insn & 0x4000 ? 'w' : 'b')
: mode_char[(insn >> 4) & (*s == 'z' ? 1 : 3)];
s += 2;
}
if (opcodep->match != (BRANCH_PC_LOW + BRANCH_INCR_HIGH * 256))
*tp++ = ' ';
if (opcodep->name[0] == 'j')
{
if (strncmp (opcodep->name, "jsr", 3) == 0)
info->insn_type = dis_jsr;
else
info->insn_type = dis_branch;
}
info->branch_delay_insns = opcodep->delayed;
for (; *s; s++)
{
switch (*s)
{
case ',':
*tp++ = *s;
break;
case '!':
break;
case 'B':
prefix_opcodep = NULL;
break;
case 'D':
case 'r':
tp = format_reg (insn & 15, tp, with_reg_prefix);
break;
case 'R':
tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix);
break;
case 'y':
case 'S':
case 's':
if ((insn & 0x400) && (insn & 15) == 15)
{
long number;
int signedp
= ((*cs == 'z' && (insn & 0x20))
|| opcodep->match == BDAP_QUICK_OPCODE);
int nbytes;
if (opcodep->imm_oprnd_size == SIZE_FIX_32)
nbytes = 4;
else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG)
{
const struct cris_spec_reg *sregp
= spec_reg_info ((insn >> 12) & 15);
if (sregp == NULL)
nbytes = 42;
else
nbytes = (sregp->reg_size + 1) & ~1;
}
else
{
int mode_size = 1 << ((insn >> 4) & (*cs == 'z' ? 1 : 3));
if (mode_size == 1)
nbytes = 2;
else
nbytes = mode_size;
}
switch (nbytes)
{
case 1:
number = buffer[2];
if (signedp && number > 127)
number -= 256;
break;
case 2:
number = buffer[2] + buffer[3] * 256;
if (signedp && number > 32767)
number -= 65536;
break;
case 4:
number
= buffer[2] + buffer[3] * 256 + buffer[4] * 65536
+ buffer[5] * 0x1000000;
break;
default:
strcpy (tp, "bug");
tp += 3;
number = 42;
}
if ((*cs == 'z' && (insn & 0x20))
|| (opcodep->match == BDAP_QUICK_OPCODE
&& (nbytes <= 2 || buffer[1 + nbytes] == 0)))
tp = format_dec (number, tp, signedp);
else
{
unsigned int highbyte = (number >> 24) & 0xff;
if (nbytes == 4
&& (highbyte == ((addr >> 24) & 0xff)
|| (highbyte != 0 && highbyte != 0xff)
|| info->insn_type == dis_branch
|| info->insn_type == dis_jsr))
{
*tp = 0;
tp = temp;
if (temp[0])
(*info->fprintf_func) (info->stream, "%s", temp);
(*info->print_address_func) ((bfd_vma) number, info);
info->target = number;
}
else
tp = format_hex (number, tp);
}
}
else
{
if (info->insn_type != dis_nonbranch)
{
int mode_size
= 1 << ((insn >> 4)
& (opcodep->args[0] == 'z' ? 1 : 3));
int size;
info->insn_type = dis_dref;
info->flags |= CRIS_DIS_FLAG_MEMREF;
if (opcodep->imm_oprnd_size == SIZE_FIX_32)
size = 4;
else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG)
{
const struct cris_spec_reg *sregp
= spec_reg_info ((insn >> 12) & 15);
if (sregp == NULL)
size = 4;
else
size = sregp->reg_size;
}
else
size = mode_size;
info->data_size = size;
}
*tp++ = '[';
if (prefix_opcodep
&& ((insn & 0x400) == 0
|| prefix_opcodep->match != DIP_OPCODE))
{
if (insn & 0x400)
{
tp = format_reg (insn & 15, tp, with_reg_prefix);
*tp++ = '=';
}
switch (prefix_opcodep->match)
{
case DIP_OPCODE:
if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15)
{
unsigned long number
= prefix_buffer[2] + prefix_buffer[3] * 256
+ prefix_buffer[4] * 65536
+ prefix_buffer[5] * 0x1000000;
info->target = (bfd_vma) number;
*tp = 0;
tp = temp;
if (temp[0])
(*info->fprintf_func) (info->stream, "%s", temp);
(*info->print_address_func) ((bfd_vma) number, info);
}
else
{
info->flags
|= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG
| CRIS_DIS_FLAG_MEM_TARGET2_MEM);
info->target2 = prefix_insn & 15;
*tp++ = '[';
tp = format_reg (prefix_insn & 15, tp,
with_reg_prefix);
if (prefix_insn & 0x400)
*tp++ = '+';
*tp++ = ']';
}
break;
case BDAP_QUICK_OPCODE:
{
int number;
number = prefix_buffer[0];
if (number > 127)
number -= 256;
tp = format_reg ((prefix_insn >> 12) & 15, tp,
with_reg_prefix);
if (number >= 0)
*tp++ = '+';
tp = format_dec (number, tp, 1);
info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;
info->target = (prefix_insn >> 12) & 15;
info->target2 = (bfd_vma) number;
break;
}
case BIAP_OPCODE:
tp = format_reg (prefix_insn & 15, tp, with_reg_prefix);
*tp++ = '+';
tp = format_reg ((prefix_insn >> 12) & 15, tp,
with_reg_prefix);
*tp++ = '.';
*tp++ = mode_char[(prefix_insn >> 4) & 3];
info->flags
|= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG
| CRIS_DIS_FLAG_MEM_TARGET_IS_REG
| ((prefix_insn & 0x8000)
? CRIS_DIS_FLAG_MEM_TARGET2_MULT4
: ((prefix_insn & 0x8000)
? CRIS_DIS_FLAG_MEM_TARGET2_MULT2 : 0)));
if (insn == 0xf83f && (prefix_insn & ~0xf000) == 0x55f)
case_offset_counter = no_of_case_offsets;
break;
case BDAP_INDIR_OPCODE:
tp = format_reg ((prefix_insn >> 12) & 15, tp,
with_reg_prefix);
if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15)
{
long number;
unsigned int nbytes;
int mode_size = 1 << ((prefix_insn >> 4) & 3);
if (mode_size == 1)
nbytes = 2;
else
nbytes = mode_size;
switch (nbytes)
{
case 1:
number = prefix_buffer[2];
if (number > 127)
number -= 256;
break;
case 2:
number = prefix_buffer[2] + prefix_buffer[3] * 256;
if (number > 32767)
number -= 65536;
break;
case 4:
number
= prefix_buffer[2] + prefix_buffer[3] * 256
+ prefix_buffer[4] * 65536
+ prefix_buffer[5] * 0x1000000;
break;
default:
strcpy (tp, "bug");
tp += 3;
number = 42;
}
info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;
info->target2 = (bfd_vma) number;
if (nbytes == 4)
{
*tp++ = '+';
*tp = 0;
tp = temp;
(*info->fprintf_func) (info->stream, "%s", temp);
(*info->print_address_func) ((bfd_vma) number, info);
}
else
{
if (number >= 0)
*tp++ = '+';
tp = format_dec (number, tp, 1);
}
}
else
{
*tp++ = '+';
*tp++ = '[';
tp = format_reg (prefix_insn & 15, tp,
with_reg_prefix);
if (prefix_insn & 0x400)
*tp++ = '+';
*tp++ = ']';
*tp++ = '.';
*tp++ = mode_char[(prefix_insn >> 4) & 3];
info->flags
|= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG
| CRIS_DIS_FLAG_MEM_TARGET2_MEM
| CRIS_DIS_FLAG_MEM_TARGET_IS_REG
| (((prefix_insn >> 4) == 2)
? 0
: (((prefix_insn >> 4) & 3) == 1
? CRIS_DIS_FLAG_MEM_TARGET2_MEM_WORD
: CRIS_DIS_FLAG_MEM_TARGET2_MEM_BYTE)));
}
break;
default:
(*info->fprintf_func) (info->stream, "?prefix-bug");
}
prefix_opcodep = NULL;
}
else
{
tp = format_reg (insn & 15, tp, with_reg_prefix);
info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;
info->target = insn & 15;
if (insn & 0x400)
*tp++ = '+';
}
*tp++ = ']';
}
break;
case 'x':
tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix);
*tp++ = '.';
*tp++ = mode_char[(insn >> 4) & 3];
break;
case 'I':
tp = format_dec (insn & 63, tp, 0);
break;
case 'b':
{
int where = buffer[2] + buffer[3] * 256;
if (where > 32767)
where -= 65536;
where += addr + 4;
if (insn == BA_PC_INCR_OPCODE)
info->insn_type = dis_branch;
else
info->insn_type = dis_condbranch;
info->target = (bfd_vma) where;
*tp = 0;
tp = temp;
(*info->fprintf_func) (info->stream, "%s%s ",
temp, cris_cc_strings[insn >> 12]);
(*info->print_address_func) ((bfd_vma) where, info);
}
break;
case 'c':
tp = format_dec (insn & 31, tp, 0);
break;
case 'C':
tp = format_dec (insn & 15, tp, 0);
break;
case 'o':
{
long offset = insn & 0xfe;
if (insn & 1)
offset |= ~0xff;
if (opcodep->match == BA_QUICK_OPCODE)
info->insn_type = dis_branch;
else
info->insn_type = dis_condbranch;
info->target = (bfd_vma) (addr + 2 + offset);
*tp = 0;
tp = temp;
(*info->fprintf_func) (info->stream, "%s", temp);
(*info->print_address_func) ((bfd_vma) (addr + 2 + offset), info);
}
break;
case 'O':
{
long number = buffer[0];
if (number > 127)
number = number - 256;
tp = format_dec (number, tp, 1);
*tp++ = ',';
tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix);
}
break;
case 'f':
tp = print_flags (insn, tp);
break;
case 'i':
tp = format_dec ((insn & 32) ? (insn & 31) | ~31 : insn & 31, tp, 1);
break;
case 'P':
{
const struct cris_spec_reg *sregp
= spec_reg_info ((insn >> 12) & 15);
if (sregp->name == NULL)
*tp++ = '?';
else
{
if (with_reg_prefix)
*tp++ = REGISTER_PREFIX_CHAR;
strcpy (tp, sregp->name);
tp += strlen (tp);
}
}
break;
default:
strcpy (tp, "???");
tp += 3;
}
}
*tp = 0;
if (prefix_opcodep)
(*info->fprintf_func) (info->stream, " (OOPS unused prefix \"%s: %s\")",
prefix_opcodep->name, prefix_opcodep->args);
(*info->fprintf_func) (info->stream, "%s", temp);
if (TRACE_CASE && case_offset_counter == 0)
{
if (strncmp (opcodep->name, "sub", 3) == 0)
case_offset = last_immediate;
else if (strncmp (opcodep->name, "add", 3) == 0)
{
case_offset = -last_immediate;
}
else if (strncmp (opcodep->name, "bound", 5) == 0)
{
no_of_case_offsets = last_immediate + 1;
}
else if (info->insn_type == dis_jsr
|| info->insn_type == dis_branch
|| info->insn_type == dis_condbranch)
case_offset = 0;
}
}
static int
print_insn_cris_generic (memaddr, info, with_reg_prefix)
bfd_vma memaddr;
disassemble_info *info;
boolean with_reg_prefix;
{
int nbytes;
unsigned int insn;
const struct cris_opcode *matchedp;
int advance = 0;
unsigned char buffer[MAX_BYTES_PER_CRIS_INSN];
unsigned char *bufp;
int status = 0;
bfd_vma addr;
for (nbytes = MAX_BYTES_PER_CRIS_INSN; nbytes > 0; nbytes -= 2)
{
status = (*info->read_memory_func) (memaddr, buffer, nbytes, info);
if (status == 0)
break;
}
if (nbytes != MAX_BYTES_PER_CRIS_INSN)
memset (buffer + nbytes, 0, MAX_BYTES_PER_CRIS_INSN - nbytes);
addr = memaddr;
bufp = buffer;
info->insn_info_valid = 1;
info->branch_delay_insns = 0;
info->data_size = 0;
info->insn_type = dis_nonbranch;
info->flags = 0;
info->target = 0;
info->target2 = 0;
if (nbytes != 0)
{
matchedp = NULL;
insn = bufp[0] + bufp[1] * 256;
if (TRACE_CASE && case_offset_counter != 0)
{
info->insn_type = dis_noninsn;
advance += 2;
(*info->fprintf_func) (info->stream, "case %d%s: -> ",
case_offset + no_of_case_offsets
- case_offset_counter,
case_offset_counter == 1 ? "/default" :
"");
(*info->print_address_func) ((bfd_vma)
((short) (insn)
+ (long) (addr
- (no_of_case_offsets
- case_offset_counter)
* 2)), info);
case_offset_counter--;
if (case_offset_counter == 0)
case_offset = 0;
}
else if (insn == 0)
{
(*info->fprintf_func) (info->stream, "bcc .+2");
info->insn_type = dis_noninsn;
advance += 2;
}
else
{
const struct cris_opcode *prefix_opcodep = NULL;
unsigned char *prefix_buffer = bufp;
unsigned int prefix_insn = insn;
int prefix_size = 0;
matchedp = get_opcode_entry (insn, NO_CRIS_PREFIX);
if (matchedp != NULL && PARSE_PREFIX && matchedp->args[0] == 'p')
{
prefix_size = bytes_to_skip (prefix_insn, matchedp);
prefix_opcodep = matchedp;
insn = bufp[prefix_size] + bufp[prefix_size + 1] * 256;
matchedp = get_opcode_entry (insn, prefix_insn);
if (matchedp != NULL)
{
addr += prefix_size;
bufp += prefix_size;
advance += prefix_size;
}
else
{
matchedp = prefix_opcodep;
insn = prefix_insn;
prefix_opcodep = NULL;
}
}
if (matchedp == NULL)
{
(*info->fprintf_func) (info->stream, "??0x%lx", insn);
advance += 2;
info->insn_type = dis_noninsn;
}
else
{
advance += bytes_to_skip (insn, matchedp);
print_with_operands (matchedp, insn, bufp, addr, info,
prefix_opcodep, prefix_insn,
prefix_buffer, with_reg_prefix);
}
}
}
else
info->insn_type = dis_noninsn;
if (status != 0 && (nbytes == 0 || advance > nbytes))
{
(*info->memory_error_func) (status, memaddr, info);
return -1;
}
info->bytes_per_line = MAX_BYTES_PER_CRIS_INSN;
info->bytes_per_chunk = 2;
info->display_endian = BFD_ENDIAN_BIG;
return advance;
}
static int
print_insn_cris_with_register_prefix (vma, info)
bfd_vma vma;
disassemble_info *info;
{
return print_insn_cris_generic (vma, info, true);
}
static int
print_insn_cris_without_register_prefix (vma, info)
bfd_vma vma;
disassemble_info *info;
{
return print_insn_cris_generic (vma, info, false);
}
disassembler_ftype
cris_get_disassembler (abfd)
bfd *abfd;
{
if (abfd == NULL || bfd_get_symbol_leading_char (abfd) == 0)
return print_insn_cris_with_register_prefix;
return print_insn_cris_without_register_prefix;
}