#include "bfd.h"
#include "sysdep.h"
#include "dis-asm.h"
#if !defined(const) && !defined(__STDC__)
#define const
#endif
#include "opcode/ns32k.h"
#include "opintl.h"
static disassemble_info *dis_info;
#define INVALID_FLOAT(val, size) invalid_float((char *)val, size)
static int print_insn_arg
PARAMS ((int, int, int *, char *, bfd_vma, char *, int));
static int get_displacement PARAMS ((char *, int *));
static int invalid_float PARAMS ((char *, int));
static long int read_memory_integer PARAMS ((unsigned char *, int));
static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *));
struct ns32k_option;
static void optlist PARAMS ((int, const struct ns32k_option *, char *));
static void list_search PARAMS ((int, const struct ns32k_option *, char *));
static int bit_extract PARAMS ((bfd_byte *, int, int));
static int bit_extract_simple PARAMS ((bfd_byte *, int, int));
static void bit_copy PARAMS ((char *, int, int, char *));
static int sign_extend PARAMS ((int, int));
static void flip_bytes PARAMS ((char *, int));
static long read_memory_integer(addr, nr)
unsigned char *addr;
int nr;
{
long val;
int i;
for (val = 0, i = nr - 1; i >= 0; i--) {
val = (val << 8);
val |= (0xff & *(addr + i));
}
return val;
}
#define MAXLEN 62
#include <setjmp.h>
struct private
{
bfd_byte *max_fetched;
bfd_byte the_buffer[MAXLEN];
bfd_vma insn_start;
jmp_buf bailout;
};
#define FETCH_DATA(info, addr) \
((addr) <= ((struct private *)(info->private_data))->max_fetched \
? 1 : fetch_data ((info), (addr)))
static int
fetch_data (info, addr)
struct disassemble_info *info;
bfd_byte *addr;
{
int status;
struct private *priv = (struct private *)info->private_data;
bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
status = (*info->read_memory_func) (start,
priv->max_fetched,
addr - priv->max_fetched,
info);
if (status != 0)
{
(*info->memory_error_func) (status, start, info);
longjmp (priv->bailout, 1);
}
else
priv->max_fetched = addr;
return 1;
}
#define NOPCODES (sizeof ns32k_opcodes / sizeof ns32k_opcodes[0])
#define NEXT_IS_ADDR '|'
struct ns32k_option {
char *pattern;
unsigned long value;
unsigned long match;
};
static const struct ns32k_option opt_u[]=
{
{ "r0", 0x80, 0x80 },
{ "r1", 0x40, 0x40 },
{ "r2", 0x20, 0x20 },
{ "r3", 0x10, 0x10 },
{ "r4", 0x08, 0x08 },
{ "r5", 0x04, 0x04 },
{ "r6", 0x02, 0x02 },
{ "r7", 0x01, 0x01 },
{ 0 , 0x00, 0x00 }
};
static const struct ns32k_option opt_U[]=
{
{ "r0", 0x01, 0x01 },
{ "r1", 0x02, 0x02 },
{ "r2", 0x04, 0x04 },
{ "r3", 0x08, 0x08 },
{ "r4", 0x10, 0x10 },
{ "r5", 0x20, 0x20 },
{ "r6", 0x40, 0x40 },
{ "r7", 0x80, 0x80 },
{ 0 , 0x00, 0x00 }
};
static const struct ns32k_option opt_O[]=
{
{ "c", 0x8, 0x8 },
{ "m", 0x4, 0x4 },
{ "f", 0x2, 0x2 },
{ "i", 0x1, 0x1 },
{ 0 , 0x0, 0x0 }
};
static const struct ns32k_option opt_C[]=
{
{ "a", 0x4, 0x4 },
{ "i", 0x2, 0x2 },
{ "d", 0x1, 0x1 },
{ 0 , 0x0, 0x0 }
};
static const struct ns32k_option opt_S[]=
{
{ "b", 0x1, 0x1 },
{ "u", 0x6, 0x6 },
{ "w", 0x2, 0x2 },
{ 0 , 0x0, 0x0 }
};
static const struct ns32k_option list_P532[]=
{
{ "us", 0x0, 0xf },
{ "dcr", 0x1, 0xf },
{ "bpc", 0x2, 0xf },
{ "dsr", 0x3, 0xf },
{ "car", 0x4, 0xf },
{ "fp", 0x8, 0xf },
{ "sp", 0x9, 0xf },
{ "sb", 0xa, 0xf },
{ "usp", 0xb, 0xf },
{ "cfg", 0xc, 0xf },
{ "psr", 0xd, 0xf },
{ "intbase", 0xe, 0xf },
{ "mod", 0xf, 0xf },
{ 0 , 0x00, 0xf }
};
static const struct ns32k_option list_M532[]=
{
{ "mcr", 0x9, 0xf },
{ "msr", 0xa, 0xf },
{ "tear", 0xb, 0xf },
{ "ptb0", 0xc, 0xf },
{ "ptb1", 0xd, 0xf },
{ "ivar0", 0xe, 0xf },
{ "ivar1", 0xf, 0xf },
{ 0 , 0x0, 0xf }
};
static const struct ns32k_option list_P032[]=
{
{ "upsr", 0x0, 0xf },
{ "fp", 0x8, 0xf },
{ "sp", 0x9, 0xf },
{ "sb", 0xa, 0xf },
{ "psr", 0xb, 0xf },
{ "intbase", 0xe, 0xf },
{ "mod", 0xf, 0xf },
{ 0 , 0x0, 0xf }
};
static const struct ns32k_option list_M032[]=
{
{ "bpr0", 0x0, 0xf },
{ "bpr1", 0x1, 0xf },
{ "pf0", 0x4, 0xf },
{ "pf1", 0x5, 0xf },
{ "sc", 0x8, 0xf },
{ "msr", 0xa, 0xf },
{ "bcnt", 0xb, 0xf },
{ "ptb0", 0xc, 0xf },
{ "ptb1", 0xd, 0xf },
{ "eia", 0xf, 0xf },
{ 0 , 0x0, 0xf }
};
static void
optlist(options, optionP, result)
int options;
const struct ns32k_option *optionP;
char *result;
{
if (options == 0) {
sprintf(result, "[]");
return;
}
sprintf(result, "[");
for (; (options != 0) && optionP->pattern; optionP++) {
if ((options & optionP->match) == optionP->value) {
strcat(result, optionP->pattern);
options &= ~optionP->value;
if (options != 0)
strcat(result, ",");
}
}
if (options != 0)
strcat(result, "undefined");
strcat(result, "]");
}
static void
list_search (reg_value, optionP, result)
int reg_value;
const struct ns32k_option *optionP;
char *result;
{
for (; optionP->pattern; optionP++) {
if ((reg_value & optionP->match) == optionP->value) {
sprintf(result, "%s", optionP->pattern);
return;
}
}
sprintf(result, "undefined");
}
static int
bit_extract (buffer, offset, count)
bfd_byte *buffer;
int offset;
int count;
{
int result;
int bit;
buffer += offset >> 3;
offset &= 7;
bit = 1;
result = 0;
while (count--)
{
FETCH_DATA(dis_info, buffer + 1);
if ((*buffer & (1 << offset)))
result |= bit;
if (++offset == 8)
{
offset = 0;
buffer++;
}
bit <<= 1;
}
return result;
}
static int
bit_extract_simple (buffer, offset, count)
bfd_byte *buffer;
int offset;
int count;
{
int result;
int bit;
buffer += offset >> 3;
offset &= 7;
bit = 1;
result = 0;
while (count--)
{
if ((*buffer & (1 << offset)))
result |= bit;
if (++offset == 8)
{
offset = 0;
buffer++;
}
bit <<= 1;
}
return result;
}
static void
bit_copy (buffer, offset, count, to)
char *buffer;
int offset;
int count;
char *to;
{
for(; count > 8; count -= 8, to++, offset += 8)
*to = bit_extract (buffer, offset, 8);
*to = bit_extract (buffer, offset, count);
}
static int
sign_extend (value, bits)
int value, bits;
{
value = value & ((1 << bits) - 1);
return (value & (1 << (bits-1))
? value | (~((1 << bits) - 1))
: value);
}
static void
flip_bytes (ptr, count)
char *ptr;
int count;
{
char tmp;
while (count > 0)
{
tmp = ptr[0];
ptr[0] = ptr[count-1];
ptr[count-1] = tmp;
ptr++;
count -= 2;
}
}
#define Is_gen(c) \
((c) == 'F' || (c) == 'L' || (c) == 'B' \
|| (c) == 'W' || (c) == 'D' || (c) == 'A' || (c) == 'I' || (c) == 'Z')
#define Adrmod_index_byte 0x1c
#define Adrmod_index_word 0x1d
#define Adrmod_index_doubleword 0x1e
#define Adrmod_index_quadword 0x1f
#define Adrmod_is_index(mode) \
(mode == Adrmod_index_byte \
|| mode == Adrmod_index_word \
|| mode == Adrmod_index_doubleword \
|| mode == Adrmod_index_quadword)
int
print_insn_ns32k (memaddr, info)
bfd_vma memaddr;
disassemble_info *info;
{
unsigned int i;
const char *d;
unsigned short first_word;
int ioffset;
int aoffset;
char arg_bufs[MAX_ARGS+1][ARG_LEN];
int argnum;
int maxarg;
struct private priv;
bfd_byte *buffer = priv.the_buffer;
dis_info = info;
info->private_data = (PTR) &priv;
priv.max_fetched = priv.the_buffer;
priv.insn_start = memaddr;
if (setjmp (priv.bailout) != 0)
return -1;
FETCH_DATA(info, buffer + 1);
for (i = 0; i < NOPCODES; i++)
if (ns32k_opcodes[i].opcode_id_size <= 8
&& ((buffer[0]
& (((unsigned long) 1 << ns32k_opcodes[i].opcode_id_size) - 1))
== ns32k_opcodes[i].opcode_seed))
break;
if (i == NOPCODES) {
FETCH_DATA(info, buffer + 2);
first_word = read_memory_integer(buffer, 2);
for (i = 0; i < NOPCODES; i++)
if ((first_word
& (((unsigned long) 1 << ns32k_opcodes[i].opcode_id_size) - 1))
== ns32k_opcodes[i].opcode_seed)
break;
if (i == NOPCODES)
{
(*dis_info->fprintf_func)(dis_info->stream, "0%o", buffer[0]);
return 1;
}
}
(*dis_info->fprintf_func)(dis_info->stream, "%s", ns32k_opcodes[i].name);
ioffset = ns32k_opcodes[i].opcode_size;
aoffset = ns32k_opcodes[i].opcode_size;
d = ns32k_opcodes[i].operands;
if (*d)
{
int index_offset[MAX_ARGS];
int whicharg = 0;
(*dis_info->fprintf_func)(dis_info->stream, "\t");
maxarg = 0;
if (Is_gen(d[1]))
{
int addr_mode = bit_extract (buffer, ioffset - 5, 5);
if (Adrmod_is_index (addr_mode))
{
aoffset += 8;
index_offset[0] = aoffset;
}
}
if (d[2] && Is_gen(d[3]))
{
int addr_mode = bit_extract (buffer, ioffset - 10, 5);
if (Adrmod_is_index (addr_mode))
{
aoffset += 8;
index_offset[1] = aoffset;
}
}
while (*d)
{
argnum = *d - '1';
d++;
if (argnum > maxarg && argnum < MAX_ARGS)
maxarg = argnum;
ioffset = print_insn_arg (*d, ioffset, &aoffset, buffer,
memaddr, arg_bufs[argnum],
index_offset[whicharg]);
d++;
whicharg++;
}
for (argnum = 0; argnum <= maxarg; argnum++)
{
bfd_vma addr;
char *ch;
for (ch = arg_bufs[argnum]; *ch;)
{
if (*ch == NEXT_IS_ADDR)
{
++ch;
addr = bfd_scan_vma (ch, NULL, 16);
(*dis_info->print_address_func) (addr, dis_info);
while (*ch && *ch != NEXT_IS_ADDR)
++ch;
if (*ch)
++ch;
}
else
(*dis_info->fprintf_func)(dis_info->stream, "%c", *ch++);
}
if (argnum < maxarg)
(*dis_info->fprintf_func)(dis_info->stream, ", ");
}
}
return aoffset / 8;
}
static int
print_insn_arg (d, ioffset, aoffsetp, buffer, addr, result, index_offset)
int d;
int ioffset, *aoffsetp;
char *buffer;
bfd_vma addr;
char *result;
int index_offset;
{
union {
float f;
double d;
int i[2];
} value;
int Ivalue;
int addr_mode;
int disp1, disp2;
int index;
int size;
switch (d)
{
case 'f':
ioffset -= 5;
case 'Z':
case 'F':
case 'L':
case 'I':
case 'B':
case 'W':
case 'D':
case 'A':
addr_mode = bit_extract (buffer, ioffset-5, 5);
ioffset -= 5;
switch (addr_mode)
{
case 0x0: case 0x1: case 0x2: case 0x3:
case 0x4: case 0x5: case 0x6: case 0x7:
switch (d)
{
case 'F':
case 'L':
case 'Z':
sprintf (result, "f%d", addr_mode);
break;
default:
sprintf (result, "r%d", addr_mode);
}
break;
case 0x8: case 0x9: case 0xa: case 0xb:
case 0xc: case 0xd: case 0xe: case 0xf:
disp1 = get_displacement (buffer, aoffsetp);
sprintf (result, "%d(r%d)", disp1, addr_mode & 7);
break;
case 0x10:
case 0x11:
case 0x12:
disp1 = get_displacement (buffer, aoffsetp);
disp2 = get_displacement (buffer, aoffsetp);
sprintf (result, "%d(%d(%s))", disp2, disp1,
addr_mode==0x10?"fp":addr_mode==0x11?"sp":"sb");
break;
case 0x13:
sprintf (result, "reserved");
break;
case 0x14:
switch (d)
{
case 'I': case 'Z': case 'A':
sprintf (result, _("$<undefined>"));
break;
case 'B':
Ivalue = bit_extract (buffer, *aoffsetp, 8);
Ivalue = sign_extend (Ivalue, 8);
*aoffsetp += 8;
sprintf (result, "$%d", Ivalue);
break;
case 'W':
Ivalue = bit_extract (buffer, *aoffsetp, 16);
flip_bytes ((char *) & Ivalue, 2);
*aoffsetp += 16;
Ivalue = sign_extend (Ivalue, 16);
sprintf (result, "$%d", Ivalue);
break;
case 'D':
Ivalue = bit_extract (buffer, *aoffsetp, 32);
flip_bytes ((char *) & Ivalue, 4);
*aoffsetp += 32;
sprintf (result, "$%d", Ivalue);
break;
case 'F':
bit_copy (buffer, *aoffsetp, 32, (char *) &value.f);
flip_bytes ((char *) &value.f, 4);
*aoffsetp += 32;
if (INVALID_FLOAT (&value.f, 4))
sprintf (result, "<<invalid float 0x%.8x>>", value.i[0]);
else
sprintf (result, "$%g", value.f);
break;
case 'L':
bit_copy (buffer, *aoffsetp, 64, (char *) &value.d);
flip_bytes ((char *) &value.d, 8);
*aoffsetp += 64;
if (INVALID_FLOAT (&value.d, 8))
sprintf (result, "<<invalid double 0x%.8x%.8x>>",
value.i[1], value.i[0]);
else
sprintf (result, "$%g", value.d);
break;
}
break;
case 0x15:
disp1 = get_displacement (buffer, aoffsetp);
sprintf (result, "@|%d|", disp1);
break;
case 0x16:
disp1 = get_displacement (buffer, aoffsetp);
disp2 = get_displacement (buffer, aoffsetp);
sprintf (result, "EXT(%d) + %d", disp1, disp2);
break;
case 0x17:
sprintf (result, "tos");
break;
case 0x18:
disp1 = get_displacement (buffer, aoffsetp);
sprintf (result, "%d(fp)", disp1);
break;
case 0x19:
disp1 = get_displacement (buffer, aoffsetp);
sprintf (result, "%d(sp)", disp1);
break;
case 0x1a:
disp1 = get_displacement (buffer, aoffsetp);
sprintf (result, "%d(sb)", disp1);
break;
case 0x1b:
disp1 = get_displacement (buffer, aoffsetp);
*result++ = NEXT_IS_ADDR;
sprintf_vma (result, addr + disp1);
result += strlen (result);
*result++ = NEXT_IS_ADDR;
*result = '\0';
break;
case 0x1c:
case 0x1d:
case 0x1e:
case 0x1f:
index = bit_extract (buffer, index_offset - 8, 3);
print_insn_arg (d, index_offset, aoffsetp, buffer, addr,
result, 0);
{
static const char *ind = "bwdq";
char *off;
off = result + strlen (result);
sprintf (off, "[r%d:%c]", index,
ind[addr_mode & 3]);
}
break;
}
break;
case 'H':
case 'q':
Ivalue = bit_extract (buffer, ioffset-4, 4);
Ivalue = sign_extend (Ivalue, 4);
sprintf (result, "%d", Ivalue);
ioffset -= 4;
break;
case 'r':
Ivalue = bit_extract (buffer, ioffset-3, 3);
sprintf (result, "r%d", Ivalue&7);
ioffset -= 3;
break;
case 'd':
sprintf (result, "%d", get_displacement (buffer, aoffsetp));
break;
case 'b':
Ivalue = get_displacement (buffer, aoffsetp);
size = bit_extract(buffer, ioffset-6, 2);
if (size == 0)
size = 1;
else if (size == 1)
size = 2;
else
size = 4;
sprintf (result, "%d", (Ivalue / size) + 1);
break;
case 'p':
*result++ = NEXT_IS_ADDR;
sprintf_vma (result, addr + get_displacement (buffer, aoffsetp));
result += strlen (result);
*result++ = NEXT_IS_ADDR;
*result = '\0';
break;
case 'i':
Ivalue = bit_extract (buffer, *aoffsetp, 8);
*aoffsetp += 8;
sprintf (result, "0x%x", Ivalue);
break;
case 'u':
Ivalue = bit_extract (buffer, *aoffsetp, 8);
optlist(Ivalue, opt_u, result);
*aoffsetp += 8;
break;
case 'U':
Ivalue = bit_extract(buffer, *aoffsetp, 8);
optlist(Ivalue, opt_U, result);
*aoffsetp += 8;
break;
case 'O':
Ivalue = bit_extract(buffer, ioffset-9, 9);
optlist(Ivalue, opt_O, result);
ioffset -= 9;
break;
case 'C':
Ivalue = bit_extract(buffer, ioffset-4, 4);
optlist(Ivalue, opt_C, result);
ioffset -= 4;
break;
case 'S':
Ivalue = bit_extract(buffer, ioffset - 8, 8);
optlist(Ivalue, opt_S, result);
ioffset -= 8;
break;
case 'M':
Ivalue = bit_extract(buffer, ioffset-4, 4);
list_search(Ivalue, 0 ? list_M032 : list_M532, result);
ioffset -= 4;
break;
case 'P':
Ivalue = bit_extract(buffer, ioffset-4, 4);
list_search(Ivalue, 0 ? list_P032 : list_P532, result);
ioffset -= 4;
break;
case 'g':
Ivalue = bit_extract(buffer, *aoffsetp, 3);
sprintf(result, "%d", Ivalue);
*aoffsetp += 3;
break;
case 'G':
Ivalue = bit_extract(buffer, *aoffsetp, 5);
sprintf(result, "%d", Ivalue + 1);
*aoffsetp += 5;
break;
}
return ioffset;
}
static int
get_displacement (buffer, aoffsetp)
char *buffer;
int *aoffsetp;
{
int Ivalue;
short Ivalue2;
Ivalue = bit_extract (buffer, *aoffsetp, 8);
switch (Ivalue & 0xc0)
{
case 0x00:
case 0x40:
Ivalue = sign_extend (Ivalue, 7);
*aoffsetp += 8;
break;
case 0x80:
Ivalue2 = bit_extract (buffer, *aoffsetp, 16);
flip_bytes ((char *) & Ivalue2, 2);
Ivalue = sign_extend (Ivalue2, 14);
*aoffsetp += 16;
break;
case 0xc0:
Ivalue = bit_extract (buffer, *aoffsetp, 32);
flip_bytes ((char *) & Ivalue, 4);
Ivalue = sign_extend (Ivalue, 30);
*aoffsetp += 32;
break;
}
return Ivalue;
}
#if 1
static int
invalid_float (p, len)
register char *p;
register int len;
{
register int val;
if ( len == 4 )
val = (bit_extract_simple(p, 23, 8) == 0xff
|| (bit_extract_simple(p, 23, 8) == 0 &&
bit_extract_simple(p, 0, 23) != 0));
else if ( len == 8 )
val = (bit_extract_simple(p, 52, 11) == 0x7ff
|| (bit_extract_simple(p, 52, 11) == 0
&& (bit_extract_simple(p, 0, 32) != 0
|| bit_extract_simple(p, 32, 20) != 0)));
else
val = 1;
return (val);
}
#else
typedef union { double d;
float f;
struct { unsigned m:23, e:8, :1;} sf;
struct { unsigned lm; unsigned m:20, e:11, :1;} sd;
} float_type_u;
static int
invalid_float (p, len)
register float_type_u *p;
register int len;
{
register int val;
if ( len == sizeof (float) )
val = (p->sf.e == 0xff
|| (p->sf.e == 0 && p->sf.m != 0));
else if ( len == sizeof (double) )
val = (p->sd.e == 0x7ff
|| (p->sd.e == 0 && (p->sd.m != 0 || p->sd.lm != 0)));
else
val = 1;
return (val);
}
#endif