#include "sysdep.h"
#include "dis-asm.h"
#include "opcode/m88k.h"
#include "opintl.h"
INSTAB *hashtable[HASHVAL] = {0};
static int
m88kdis PARAMS ((bfd_vma, unsigned long, struct disassemble_info *));
static void
printop PARAMS ((struct disassemble_info *, OPSPEC *, unsigned long, bfd_vma, int));
static void
init_disasm PARAMS ((void));
static void
install PARAMS ((INSTAB *instptr));
int
print_insn_m88k (memaddr, info)
bfd_vma memaddr;
struct disassemble_info *info;
{
bfd_byte buffer[4];
int status;
memaddr &=~ (bfd_vma) 3;
status = (*info->read_memory_func) (memaddr, buffer, 4, info);
if (status != 0)
{
(*info->memory_error_func) (status, memaddr, info);
return -1;
}
return m88kdis (memaddr, bfd_getb32 (buffer), info);
}
static int
m88kdis (pc, instruction, info)
bfd_vma pc;
unsigned long instruction;
struct disassemble_info *info;
{
static int ihashtab_initialized = 0;
unsigned int opcode;
INSTAB *entry_ptr;
int opmask;
unsigned int class;
if (! ihashtab_initialized)
init_disasm ();
opmask = DEFMASK;
class = instruction & DEFMASK;
if ((class >= SFU0) && (class <= SFU7))
{
if (instruction < SFU1)
opmask = CTRLMASK;
else
opmask = SFUMASK;
}
else if (class == RRR)
opmask = RRRMASK;
else if (class == RRI10)
opmask = RRI10MASK;
opcode = instruction & opmask;
for (entry_ptr = hashtable[opcode % HASHVAL];
(entry_ptr != NULL) && (entry_ptr->opcode != opcode);
entry_ptr = entry_ptr->next)
;
if (entry_ptr == NULL)
(*info->fprintf_func) (info->stream, "word\t%08x", instruction);
else
{
(*info->fprintf_func) (info->stream, "%s", entry_ptr->mnemonic);
printop (info, &(entry_ptr->op1), instruction, pc, 1);
printop (info, &(entry_ptr->op2), instruction, pc, 0);
printop (info, &(entry_ptr->op3), instruction, pc, 0);
}
return 4;
}
static void
printop (info, opptr, inst, pc, first)
struct disassemble_info *info;
OPSPEC *opptr;
unsigned long inst;
bfd_vma pc;
int first;
{
int extracted_field;
char *cond_mask_sym;
if (opptr->width == 0)
return;
if (! first)
{
switch (opptr->type)
{
case REGSC:
case CONT:
break;
default:
(*info->fprintf_func) (info->stream, ",");
break;
}
}
switch (opptr->type)
{
case CRREG:
(*info->fprintf_func) (info->stream, "cr%d",
UEXT (inst, opptr->offset, opptr->width));
break;
case FCRREG:
(*info->fprintf_func) (info->stream, "fcr%d",
UEXT (inst, opptr->offset, opptr->width));
break;
case REGSC:
(*info->fprintf_func) (info->stream, "[r%d]",
UEXT (inst, opptr->offset, opptr->width));
break;
case REG:
(*info->fprintf_func) (info->stream, "r%d",
UEXT (inst, opptr->offset, opptr->width));
break;
case XREG:
(*info->fprintf_func) (info->stream, "x%d",
UEXT (inst, opptr->offset, opptr->width));
break;
case HEX:
extracted_field = UEXT (inst, opptr->offset, opptr->width);
if (extracted_field == 0)
(*info->fprintf_func) (info->stream, "0");
else
(*info->fprintf_func) (info->stream, "0x%02x", extracted_field);
break;
case DEC:
extracted_field = UEXT (inst, opptr->offset, opptr->width);
(*info->fprintf_func) (info->stream, "%d", extracted_field);
break;
case CONDMASK:
extracted_field = UEXT (inst, opptr->offset, opptr->width);
switch (extracted_field & 0x0f)
{
case 0x1: cond_mask_sym = "gt0"; break;
case 0x2: cond_mask_sym = "eq0"; break;
case 0x3: cond_mask_sym = "ge0"; break;
case 0xc: cond_mask_sym = "lt0"; break;
case 0xd: cond_mask_sym = "ne0"; break;
case 0xe: cond_mask_sym = "le0"; break;
default: cond_mask_sym = NULL; break;
}
if (cond_mask_sym != NULL)
(*info->fprintf_func) (info->stream, "%s", cond_mask_sym);
else
(*info->fprintf_func) (info->stream, "%x", extracted_field);
break;
case PCREL:
(*info->print_address_func)
(pc + (4 * (SEXT (inst, opptr->offset, opptr->width))),
info);
break;
case CONT:
(*info->fprintf_func) (info->stream, "%d,r%d",
UEXT (inst, opptr->offset, 5),
UEXT (inst, (opptr->offset) + 5, 5));
break;
case BF:
(*info->fprintf_func) (info->stream, "%d<%d>",
UEXT (inst, (opptr->offset) + 5, 5),
UEXT (inst, opptr->offset, 5));
break;
default:
(*info->fprintf_func) (info->stream, _("# <dis error: %08x>"), inst);
}
}
static void
init_disasm ()
{
int i, size;
for (i = 0; i < HASHVAL; i++)
hashtable[i] = NULL;
size = sizeof (instructions) / sizeof (INSTAB);
for (i = 0; i < size; i++)
install (&instructions[i]);
}
static void
install (instptr)
INSTAB *instptr;
{
unsigned int i;
i = (instptr->opcode) % HASHVAL;
instptr->next = hashtable[i];
hashtable[i] = instptr;
}