422 lines
12 KiB
C
422 lines
12 KiB
C
/* Print National Semiconductor 32000 instructions.
|
||
Copyright 1986, 88, 91, 92, 94, 95, 1998 Free Software Foundation, Inc.
|
||
|
||
This file is part of opcodes library.
|
||
|
||
This program is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 2 of the License, or
|
||
(at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program; if not, write to the Free Software
|
||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||
|
||
|
||
#include "bfd.h"
|
||
#include "sysdep.h"
|
||
#include "dis-asm.h"
|
||
#if !defined(const) && !defined(__STDC__)
|
||
#define const
|
||
#endif
|
||
#include "opcode/vax.h"
|
||
|
||
static disassemble_info *dis_info;
|
||
|
||
/*
|
||
* Hacks to get it to compile <= READ THESE AS FIXES NEEDED
|
||
*/
|
||
#define CORE_ADDR unsigned long
|
||
#define INVALID_FLOAT(val, size) invalid_float((char *)val, size)
|
||
#define ARG_LEN 128
|
||
struct varg
|
||
{
|
||
char arg_str[ARG_LEN];
|
||
int arg_flags;
|
||
int arg_address;
|
||
};
|
||
|
||
#if 0
|
||
static int invalid_float PARAMS ((char *, int));
|
||
#endif
|
||
|
||
static int read_memory_integer(addr, nr)
|
||
unsigned char *addr;
|
||
int nr;
|
||
{
|
||
long val;
|
||
switch (nr)
|
||
{
|
||
case 1: val = *(char *) addr; break;
|
||
case 2: val = (((char *) addr)[1] << 8) | addr[0]; break;
|
||
case 4: val = (((char *) addr)[3] << 24)
|
||
| (addr[2] << 16) | (addr[1] << 8) | (addr[0] << 0); break;
|
||
}
|
||
return val;
|
||
}
|
||
|
||
/* VAX instructions are never longer than this. */
|
||
#define MAXARGS 6
|
||
#define MAXLEN (2+MAXARGS*6)
|
||
|
||
#include <setjmp.h>
|
||
|
||
struct private
|
||
{
|
||
/* Points to first byte not fetched. */
|
||
bfd_byte *max_fetched;
|
||
bfd_byte the_buffer[MAXLEN];
|
||
bfd_vma insn_start;
|
||
jmp_buf bailout;
|
||
};
|
||
|
||
|
||
/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
|
||
to ADDR (exclusive) are valid. Returns 1 for success, longjmps
|
||
on error. */
|
||
#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;
|
||
}
|
||
|
||
/* Number of elements in the opcode table. */
|
||
#define NOPCODES (sizeof vax_opcodes / sizeof vax_opcodes[0])
|
||
|
||
static const char * const vax_regs[16] =
|
||
{
|
||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||
"r8", "r9", "r10", "r11", "ap", "fp", "sp", "pc"
|
||
};
|
||
static const char * const vax_literal_floats[64] =
|
||
{
|
||
"0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", "0.9375",
|
||
"1.0", "1.125", "1.25", "1.375", "1.5", "1.625", "1.75", "1.875",
|
||
"2.0", "2.25", "2.5", "2.75", "3.0", "3.25", "3.5", "3.75",
|
||
"4.0", "4.5", "5.0", "5.5", "6.0", "6.5", "7.0", "7.5",
|
||
"8.0", "9.0", "10.0", "11.0", "12.0", "13.0", "14.0", "15.0",
|
||
"16.0", "18.0", "20.0", "22.0", "24.0", "26.0", "28.0", "30.0",
|
||
"32.0", "36.0", "40.0", "44.0", "48.0", "52.0", "56.0", "60.0",
|
||
"64.0", "72.0", "80.0", "88.0", "96.0", "104.0", "112.0", "120.0",
|
||
|
||
};
|
||
|
||
static const int vax_disp_masks[5] = { 0, 0xff, 0xffff, 0xffffff, 0xffffffff };
|
||
|
||
#define ARG_BYTE 0x0001
|
||
#define ARG_WORD 0x0002
|
||
#define ARG_LONGWORD 0x0004
|
||
#define ARG_QUADWORD 0x0008
|
||
#define ARG_OCTAWORD 0x0010
|
||
#define ARG_F_FLOAT 0x0104
|
||
#define ARG_D_FLOAT 0x0208
|
||
#define ARG_G_FLOAT 0x0308
|
||
#define ARG_H_FLOAT 0x0410
|
||
#define ARG_DEFERRED 0x1000
|
||
#define ARG_ADDRESS 0x2000
|
||
|
||
#define ARG_FLOAT(f) (((f) >> 8) & 0x04)
|
||
#define ARG_SIZE(f) ((f) & 0xFF)
|
||
|
||
/* Print the VAX instruction at address MEMADDR in debugged memory,
|
||
on STREAM. Returns length of the instruction, in bytes. */
|
||
|
||
int
|
||
print_insn_vax (memaddr, info)
|
||
bfd_vma memaddr;
|
||
disassemble_info *info;
|
||
{
|
||
register const char *ap;
|
||
unsigned short first_word;
|
||
int aoffset = 1; /* bytes into instruction */
|
||
struct varg args[MAXARGS+1], *arg;
|
||
int argcnt = 0;
|
||
struct private priv;
|
||
bfd_byte *buffer = priv.the_buffer;
|
||
const struct vot *vot;
|
||
|
||
dis_info = info;
|
||
|
||
info->private_data = (PTR) &priv;
|
||
priv.max_fetched = priv.the_buffer;
|
||
priv.insn_start = memaddr;
|
||
if (setjmp (priv.bailout) != 0)
|
||
/* Error return. */
|
||
return -1;
|
||
|
||
#ifdef notyet
|
||
if ((*dis_info->symbol_at_address_func)(memaddr, info))
|
||
{
|
||
FETCH_DATA(info, buffer + 2);
|
||
(*dis_info->fprintf_func)(dis_info->stream,
|
||
"\t.word\t0x%02x%02x",
|
||
buffer[1], buffer[0]);
|
||
return 2;
|
||
}
|
||
#endif
|
||
/* Look for 8bit opcodes first. Otherwise, fetching two bytes could take
|
||
* us over the end of accessible data unnecessarilly
|
||
*/
|
||
FETCH_DATA(info, buffer + 1);
|
||
for (vot = votstrs; vot->vot_name[0] != '\0'; vot++)
|
||
if ((buffer[0] == vot->vot_detail.vot_code))
|
||
break;
|
||
if (vot->vot_name == NULL) {
|
||
/* Maybe it is 16 bits big */
|
||
FETCH_DATA(info, buffer + 2);
|
||
first_word = read_memory_integer(buffer, 2);
|
||
|
||
for (vot = votstrs; vot->vot_name[0] != '\0'; vot++)
|
||
if (first_word == vot->vot_detail.vot_code)
|
||
break;
|
||
|
||
/* Handle undefined instructions. */
|
||
if (vot->vot_name[0] == '\0')
|
||
{
|
||
(*dis_info->fprintf_func)(dis_info->stream, "%02x", buffer[0]);
|
||
return 1;
|
||
}
|
||
aoffset = 2;
|
||
}
|
||
|
||
for (ap = vot->vot_detail.args, arg = args; *ap; ap += 2, arg++, argcnt++)
|
||
{
|
||
char *cp = arg->arg_str;
|
||
arg->arg_flags = 0;
|
||
cp[0] = '\0';
|
||
switch (ap[1])
|
||
{
|
||
case 'o': /* octaword */ arg->arg_flags = ARG_OCTAWORD; break;
|
||
case 'q': /* quadword */ arg->arg_flags = ARG_QUADWORD; break;
|
||
case 'l': /* longword */ arg->arg_flags = ARG_LONGWORD; break;
|
||
case 'w': /* word */ arg->arg_flags = ARG_WORD; break;
|
||
case 'b': /* byte */ arg->arg_flags = ARG_BYTE; break;
|
||
case 'f': /* f-float */ arg->arg_flags = ARG_F_FLOAT; break;
|
||
case 'd': /* d-float */ arg->arg_flags = ARG_D_FLOAT; break;
|
||
case 'g': /* g-float */ arg->arg_flags = ARG_G_FLOAT; break;
|
||
case 'h': /* h-float */ arg->arg_flags = ARG_H_FLOAT; break;
|
||
}
|
||
switch (ap[0])
|
||
{
|
||
case 'b': /* branch displacement */
|
||
{
|
||
int displacement;
|
||
FETCH_DATA(info, buffer + aoffset + ARG_SIZE(arg->arg_flags));
|
||
displacement = read_memory_integer(buffer+aoffset, ARG_SIZE(arg->arg_flags));
|
||
aoffset += ARG_SIZE(arg->arg_flags);
|
||
arg->arg_flags |= ARG_ADDRESS;
|
||
arg->arg_address = priv.insn_start + aoffset + displacement;
|
||
break;
|
||
}
|
||
|
||
case 'v': /* bit base */
|
||
case 'a': /* address of */
|
||
case 'm': /* modify */
|
||
case 'r': /* read */
|
||
case 'w': /* write */
|
||
{
|
||
int index_reg_no = -1;
|
||
int reg_no, mode;
|
||
FETCH_DATA(info, buffer + aoffset + 1);
|
||
reg_no = buffer[aoffset] & 0x0f;
|
||
mode = buffer[aoffset] >> 4;
|
||
aoffset++;
|
||
retry:
|
||
switch (mode)
|
||
{
|
||
case 4: /* index mode */
|
||
index_reg_no = reg_no;
|
||
FETCH_DATA(info, buffer + aoffset + 1);
|
||
reg_no = buffer[aoffset] & 0x0f;
|
||
mode = buffer[aoffset] >> 4;
|
||
aoffset++;
|
||
goto retry;
|
||
case 0: case 1: case 2: case 3: /* short literal */
|
||
if (!ARG_FLOAT(arg->arg_flags))
|
||
{
|
||
cp += sprintf(cp, "$%d", buffer[aoffset-1]);
|
||
}
|
||
else
|
||
{
|
||
*cp++ = '$';
|
||
strcpy(cp, vax_literal_floats[buffer[aoffset-1]]);
|
||
}
|
||
break;
|
||
case 5: /* register mode */
|
||
cp += sprintf(cp, "%s", vax_regs[reg_no]);
|
||
break;
|
||
case 6: /* register deferred */
|
||
cp += sprintf(cp, "(%s)", vax_regs[reg_no]);
|
||
break;
|
||
case 7: /* auto decrement */
|
||
cp += sprintf(cp, "-(%s)", vax_regs[reg_no]);
|
||
break;
|
||
case 8: /* auto increment */
|
||
if (reg_no == 15)
|
||
{
|
||
FETCH_DATA(info, buffer + aoffset + ARG_SIZE(arg->arg_flags));
|
||
if (!ARG_FLOAT(arg->arg_flags))
|
||
{
|
||
int i;
|
||
cp += sprintf(cp, "$0x");
|
||
for (i = ARG_SIZE(arg->arg_flags) - 1; i >= 0; i--)
|
||
cp += sprintf(cp, "%02x", buffer[aoffset + i]);
|
||
}
|
||
else
|
||
{
|
||
int i;
|
||
cp += sprintf(cp, "$0x");
|
||
for (i = ARG_SIZE(arg->arg_flags) - 1; i >= 0; i--)
|
||
cp += sprintf(cp, "%02x", buffer[aoffset + i]);
|
||
}
|
||
aoffset += ARG_SIZE(arg->arg_flags);
|
||
} else {
|
||
cp += sprintf(cp, "(%s)+", vax_regs[reg_no]);
|
||
}
|
||
break;
|
||
case 9: /* auto incr deferred */
|
||
{
|
||
if (reg_no == 15)
|
||
{
|
||
FETCH_DATA(info, buffer + aoffset + 4);
|
||
arg->arg_flags |= ARG_ADDRESS;
|
||
arg->arg_address = read_memory_integer(buffer + aoffset, 4);
|
||
strcpy(cp, "*");
|
||
aoffset += 4;
|
||
}
|
||
else
|
||
{
|
||
cp += sprintf(cp, "*(%s)+", vax_regs[reg_no]);
|
||
}
|
||
break;
|
||
}
|
||
case 10: case 11: /* byte relative */
|
||
case 12: case 13: /* word relative */
|
||
case 14: case 15: /* longword relative */
|
||
{
|
||
int n = 1 << ((mode - 10) >> 1);
|
||
int displacement;
|
||
FETCH_DATA(info, buffer + aoffset + n);
|
||
displacement = read_memory_integer(buffer + aoffset, n);
|
||
if (mode & 1)
|
||
{
|
||
*cp++ = '*';
|
||
arg->arg_flags |= ARG_DEFERRED;
|
||
}
|
||
aoffset += n;
|
||
if (reg_no == 15)
|
||
{
|
||
arg->arg_flags |= ARG_ADDRESS;
|
||
arg->arg_address = priv.insn_start + aoffset + displacement;
|
||
*cp++ = '\0';
|
||
}
|
||
else
|
||
{
|
||
cp += sprintf(cp, "%d(%s)", displacement, vax_regs[reg_no]);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
if (index_reg_no != -1)
|
||
sprintf(cp, "[%s]", vax_regs[index_reg_no]);
|
||
}
|
||
}
|
||
}
|
||
|
||
(*dis_info->fprintf_func)(dis_info->stream, "\t%s", vot->vot_name);
|
||
|
||
for (arg = args; argcnt-- > 0; arg++)
|
||
{
|
||
if (arg == args)
|
||
{
|
||
(*dis_info->fprintf_func)(dis_info->stream, "\t");
|
||
}
|
||
else
|
||
{
|
||
(*dis_info->fprintf_func)(dis_info->stream, ", ");
|
||
}
|
||
(*dis_info->fprintf_func)(dis_info->stream, arg->arg_str);
|
||
if (arg->arg_flags & ARG_ADDRESS)
|
||
{
|
||
(*dis_info->print_address_func) (arg->arg_address, dis_info);
|
||
}
|
||
}
|
||
return aoffset;
|
||
}
|
||
|
||
#if 0
|
||
#if 0 /* a version that should work on vax f's&d's on any machine */
|
||
static int
|
||
invalid_float (p, len)
|
||
register char *p;
|
||
register int len;
|
||
{
|
||
register int val;
|
||
|
||
if ( len == 4 )
|
||
val = (bit_extract(p, 23, 8)/*exponent*/ == 0xff
|
||
|| (bit_extract(p, 23, 8)/*exponent*/ == 0 &&
|
||
bit_extract(p, 0, 23)/*mantisa*/ != 0));
|
||
else if ( len == 8 )
|
||
val = (bit_extract(p, 52, 11)/*exponent*/ == 0x7ff
|
||
|| (bit_extract(p, 52, 11)/*exponent*/ == 0
|
||
&& (bit_extract(p, 0, 32)/*low mantisa*/ != 0
|
||
|| bit_extract(p, 32, 20)/*high mantisa*/ != 0)));
|
||
else
|
||
val = 1;
|
||
return (val);
|
||
}
|
||
#else
|
||
|
||
/* assumes the bytes have been swapped to local order */
|
||
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
|
||
#endif
|