42639e838c
upper and lower insn #ifndef VERTICAL_BAR_SEPARATOR.
199 lines
5.5 KiB
C
199 lines
5.5 KiB
C
/* Instruction printing code for the TXVU
|
|
Copyright (C) 1998 Free Software Foundation, Inc.
|
|
|
|
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 "dis-asm.h"
|
|
#include "opcode/txvu.h"
|
|
#include "elf-bfd.h"
|
|
#include "elf/txvu.h"
|
|
|
|
static void print_insn PARAMS ((bfd_vma, disassemble_info *, TXVU_INSN, int));
|
|
|
|
/* Print one instruction from PC on INFO->STREAM.
|
|
Return the size of the instruction. */
|
|
|
|
int
|
|
print_insn_txvu (pc, info)
|
|
bfd_vma pc;
|
|
disassemble_info *info;
|
|
{
|
|
bfd_byte buffer[8];
|
|
void *stream = info->stream;
|
|
fprintf_ftype func = info->fprintf_func;
|
|
int status;
|
|
/* First element is upper, second is lower. */
|
|
TXVU_INSN upper,lower;
|
|
static int initialized = 0;
|
|
|
|
if (!initialized)
|
|
{
|
|
initialized = 1;
|
|
txvu_opcode_init_tables (0);
|
|
}
|
|
|
|
status = (*info->read_memory_func) (pc, buffer, 8, info);
|
|
if (status != 0)
|
|
{
|
|
(*info->memory_error_func) (status, pc, info);
|
|
return -1;
|
|
}
|
|
upper = bfd_getl32 (buffer);
|
|
lower = bfd_getl32 (buffer + 4);
|
|
|
|
/* FIXME: This will need revisiting. */
|
|
print_insn (pc, info, upper, 0);
|
|
#ifdef VERTICAL_BAR_SEPARATOR
|
|
(*func) (stream, " | ");
|
|
#else
|
|
/* Not sure how much whitespace to print here.
|
|
At least two spaces, not more than 9, and having columns line up somewhat
|
|
seems reasonable. */
|
|
(*func) (stream, " \t");
|
|
#endif
|
|
print_insn (pc, info, lower, 1);
|
|
|
|
return 8;
|
|
}
|
|
|
|
/* Print one instruction.
|
|
LOWER_P is non-zero if disassembling a lower slot insn. */
|
|
|
|
static void
|
|
print_insn (pc, info, insn, lower_p)
|
|
bfd_vma pc;
|
|
disassemble_info *info;
|
|
TXVU_INSN insn;
|
|
int lower_p;
|
|
{
|
|
const struct txvu_opcode *opcode;
|
|
void *stream = info->stream;
|
|
fprintf_ftype func = info->fprintf_func;
|
|
|
|
/* The instructions are stored in lists hashed by the insn code
|
|
(though we needn't care how they're hashed). */
|
|
|
|
if (lower_p)
|
|
opcode = txvu_lower_opcode_lookup_dis (insn);
|
|
else
|
|
opcode = txvu_upper_opcode_lookup_dis (insn);
|
|
for ( ; opcode != NULL; opcode = TXVU_OPCODE_NEXT_DIS (opcode))
|
|
{
|
|
const unsigned char *syn;
|
|
int mods,invalid,num_operands;
|
|
long value;
|
|
const struct txvu_operand *operand;
|
|
|
|
/* Basic bit mask must be correct. */
|
|
if ((insn & opcode->mask) != opcode->value)
|
|
continue;
|
|
|
|
/* Make two passes over the operands. First see if any of them
|
|
have extraction functions, and, if they do, make sure the
|
|
instruction is valid. */
|
|
|
|
txvu_opcode_init_print ();
|
|
invalid = 0;
|
|
|
|
for (syn = opcode->syntax; *syn; ++syn)
|
|
{
|
|
int index;
|
|
|
|
if (*syn < 128)
|
|
continue;
|
|
|
|
mods = 0;
|
|
index = TXVU_OPERAND_INDEX (*syn);
|
|
while (TXVU_MOD_P (txvu_operands[index].flags))
|
|
{
|
|
mods |= txvu_operands[index].flags & TXVU_MOD_BITS;
|
|
++syn;
|
|
index = TXVU_OPERAND_INDEX (*syn);
|
|
}
|
|
operand = txvu_operands + index;
|
|
if (operand->extract)
|
|
(*operand->extract) (insn, operand, mods, &invalid);
|
|
}
|
|
if (invalid)
|
|
continue;
|
|
|
|
/* The instruction is valid. */
|
|
|
|
(*func) (stream, "%s", opcode->mnemonic);
|
|
num_operands = 0;
|
|
for (syn = opcode->syntax; *syn; ++syn)
|
|
{
|
|
int index;
|
|
|
|
if (*syn < 128)
|
|
{
|
|
(*func) (stream, "%c", *syn);
|
|
continue;
|
|
}
|
|
|
|
/* We have an operand. Fetch any special modifiers. */
|
|
mods = 0;
|
|
index = TXVU_OPERAND_INDEX (*syn);
|
|
while (TXVU_MOD_P (txvu_operands[index].flags))
|
|
{
|
|
mods |= txvu_operands[index].flags & TXVU_MOD_BITS;
|
|
++syn;
|
|
index = TXVU_OPERAND_INDEX (*syn);
|
|
}
|
|
operand = txvu_operands + index;
|
|
|
|
/* Extract the value from the instruction. */
|
|
if (operand->extract)
|
|
{
|
|
value = (*operand->extract) (insn, operand, mods, (int *) NULL);
|
|
}
|
|
else
|
|
{
|
|
value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
|
|
if ((operand->flags & TXVU_OPERAND_SIGNED)
|
|
&& (value & (1 << (operand->bits - 1))))
|
|
value -= 1 << operand->bits;
|
|
}
|
|
|
|
/* If second or later operand, print a comma. */
|
|
if (num_operands > 0)
|
|
(*func) (stream, ",");
|
|
|
|
/* Print the operand as directed by the flags. */
|
|
if (operand->print)
|
|
(*operand->print) (info, insn, value);
|
|
else if (operand->flags & TXVU_OPERAND_FAKE)
|
|
; /* nothing to do (??? at least not yet) */
|
|
else if (operand->flags & TXVU_OPERAND_RELATIVE_BRANCH)
|
|
(*info->print_address_func) (pc + value, info);
|
|
/* ??? Not all cases of this are currently caught. */
|
|
else if (operand->flags & TXVU_OPERAND_ABSOLUTE_BRANCH)
|
|
(*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
|
|
else if (operand->flags & TXVU_OPERAND_ADDRESS)
|
|
(*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
|
|
else
|
|
(*func) (stream, "%ld", value);
|
|
|
|
if (! (operand->flags & TXVU_OPERAND_SUFFIX))
|
|
++num_operands;
|
|
}
|
|
|
|
/* We have found and printed an instruction; return. */
|
|
return;
|
|
}
|
|
|
|
(*func) (stream, "*unknown*");
|
|
}
|