OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [opcodes/] [microblaze-dis.c] - Diff between revs 834 and 842

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 834 Rev 842
/* Disassemble Xilinx microblaze instructions.
/* Disassemble Xilinx microblaze instructions.
 
 
   Copyright 2009 Free Software Foundation, Inc.
   Copyright 2009 Free Software Foundation, Inc.
 
 
   This file is part of the GNU opcodes library.
   This file is part of the GNU opcodes library.
 
 
   This library is free software; you can redistribute it and/or modify
   This library is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   the Free Software Foundation; either version 3, or (at your option)
   any later version.
   any later version.
 
 
   It is distributed in the hope that it will be useful, but WITHOUT
   It is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
   License for more details.
   License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this file; see the file COPYING.  If not, write to the
   along with this file; see the file COPYING.  If not, write to the
   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */
   MA 02110-1301, USA.  */
 
 
 
 
#include "sysdep.h"
#include "sysdep.h"
#define STATIC_TABLE
#define STATIC_TABLE
#define DEFINE_TABLE
#define DEFINE_TABLE
 
 
#include "dis-asm.h"
#include "dis-asm.h"
#include <strings.h>
#include <strings.h>
#include "microblaze-opc.h"
#include "microblaze-opc.h"
#include "microblaze-dis.h"
#include "microblaze-dis.h"
 
 
#define get_field_rd(instr)        get_field (instr, RD_MASK, RD_LOW)
#define get_field_rd(instr)        get_field (instr, RD_MASK, RD_LOW)
#define get_field_r1(instr)        get_field (instr, RA_MASK, RA_LOW)
#define get_field_r1(instr)        get_field (instr, RA_MASK, RA_LOW)
#define get_field_r2(instr)        get_field (instr, RB_MASK, RB_LOW)
#define get_field_r2(instr)        get_field (instr, RB_MASK, RB_LOW)
#define get_int_field_imm(instr)   ((instr & IMM_MASK) >> IMM_LOW)
#define get_int_field_imm(instr)   ((instr & IMM_MASK) >> IMM_LOW)
#define get_int_field_r1(instr)    ((instr & RA_MASK) >> RA_LOW)
#define get_int_field_r1(instr)    ((instr & RA_MASK) >> RA_LOW)
 
 
 
 
 
 
static char *
static char *
get_field (long instr, long mask, unsigned short low)
get_field (long instr, long mask, unsigned short low)
{
{
  char tmpstr[25];
  char tmpstr[25];
 
 
  sprintf (tmpstr, "%s%d", register_prefix, (int)((instr & mask) >> low));
  sprintf (tmpstr, "%s%d", register_prefix, (int)((instr & mask) >> low));
  return (strdup (tmpstr));
  return (strdup (tmpstr));
}
}
 
 
static char *
static char *
get_field_imm (long instr)
get_field_imm (long instr)
{
{
  char tmpstr[25];
  char tmpstr[25];
 
 
  sprintf (tmpstr, "%d", (short)((instr & IMM_MASK) >> IMM_LOW));
  sprintf (tmpstr, "%d", (short)((instr & IMM_MASK) >> IMM_LOW));
  return (strdup (tmpstr));
  return (strdup (tmpstr));
}
}
 
 
static char *
static char *
get_field_imm5 (long instr)
get_field_imm5 (long instr)
{
{
  char tmpstr[25];
  char tmpstr[25];
 
 
  sprintf (tmpstr, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW));
  sprintf (tmpstr, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW));
  return (strdup (tmpstr));
  return (strdup (tmpstr));
}
}
 
 
static char *
static char *
get_field_rfsl (long instr)
get_field_rfsl (long instr)
{
{
  char tmpstr[25];
  char tmpstr[25];
 
 
  sprintf (tmpstr, "%s%d", fsl_register_prefix,
  sprintf (tmpstr, "%s%d", fsl_register_prefix,
           (short)((instr & RFSL_MASK) >> IMM_LOW));
           (short)((instr & RFSL_MASK) >> IMM_LOW));
  return (strdup (tmpstr));
  return (strdup (tmpstr));
}
}
 
 
static char *
static char *
get_field_imm15 (long instr)
get_field_imm15 (long instr)
{
{
  char tmpstr[25];
  char tmpstr[25];
 
 
  sprintf (tmpstr, "%d", (short)((instr & IMM15_MASK) >> IMM_LOW));
  sprintf (tmpstr, "%d", (short)((instr & IMM15_MASK) >> IMM_LOW));
  return (strdup (tmpstr));
  return (strdup (tmpstr));
}
}
 
 
static char *
static char *
get_field_special (long instr, struct op_code_struct * op)
get_field_special (long instr, struct op_code_struct * op)
{
{
  char tmpstr[25];
  char tmpstr[25];
  char spr[6];
  char spr[6];
 
 
  switch ((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask))
  switch ((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask))
    {
    {
    case REG_MSR_MASK :
    case REG_MSR_MASK :
      strcpy (spr, "msr");
      strcpy (spr, "msr");
      break;
      break;
    case REG_PC_MASK :
    case REG_PC_MASK :
      strcpy (spr, "pc");
      strcpy (spr, "pc");
      break;
      break;
    case REG_EAR_MASK :
    case REG_EAR_MASK :
      strcpy (spr, "ear");
      strcpy (spr, "ear");
      break;
      break;
    case REG_ESR_MASK :
    case REG_ESR_MASK :
      strcpy (spr, "esr");
      strcpy (spr, "esr");
      break;
      break;
    case REG_FSR_MASK :
    case REG_FSR_MASK :
      strcpy (spr, "fsr");
      strcpy (spr, "fsr");
      break;
      break;
    case REG_BTR_MASK :
    case REG_BTR_MASK :
      strcpy (spr, "btr");
      strcpy (spr, "btr");
      break;
      break;
    case REG_EDR_MASK :
    case REG_EDR_MASK :
      strcpy (spr, "edr");
      strcpy (spr, "edr");
      break;
      break;
    case REG_PID_MASK :
    case REG_PID_MASK :
      strcpy (spr, "pid");
      strcpy (spr, "pid");
      break;
      break;
    case REG_ZPR_MASK :
    case REG_ZPR_MASK :
      strcpy (spr, "zpr");
      strcpy (spr, "zpr");
      break;
      break;
    case REG_TLBX_MASK :
    case REG_TLBX_MASK :
      strcpy (spr, "tlbx");
      strcpy (spr, "tlbx");
      break;
      break;
    case REG_TLBLO_MASK :
    case REG_TLBLO_MASK :
      strcpy (spr, "tlblo");
      strcpy (spr, "tlblo");
      break;
      break;
    case REG_TLBHI_MASK :
    case REG_TLBHI_MASK :
      strcpy (spr, "tlbhi");
      strcpy (spr, "tlbhi");
      break;
      break;
    case REG_TLBSX_MASK :
    case REG_TLBSX_MASK :
      strcpy (spr, "tlbsx");
      strcpy (spr, "tlbsx");
      break;
      break;
    default :
    default :
      if (((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) & 0xE000)
      if (((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) & 0xE000)
          == REG_PVR_MASK)
          == REG_PVR_MASK)
        {
        {
          sprintf (tmpstr, "%spvr%d", register_prefix,
          sprintf (tmpstr, "%spvr%d", register_prefix,
                   (unsigned short)(((instr & IMM_MASK) >> IMM_LOW)
                   (unsigned short)(((instr & IMM_MASK) >> IMM_LOW)
                                    ^ op->immval_mask) ^ REG_PVR_MASK);
                                    ^ op->immval_mask) ^ REG_PVR_MASK);
          return (strdup (tmpstr));
          return (strdup (tmpstr));
        }
        }
      else
      else
        strcpy (spr, "pc");
        strcpy (spr, "pc");
      break;
      break;
    }
    }
 
 
   sprintf (tmpstr, "%s%s", register_prefix, spr);
   sprintf (tmpstr, "%s%s", register_prefix, spr);
   return (strdup (tmpstr));
   return (strdup (tmpstr));
}
}
 
 
static unsigned long
static unsigned long
read_insn_microblaze (bfd_vma memaddr,
read_insn_microblaze (bfd_vma memaddr,
                      struct disassemble_info *info,
                      struct disassemble_info *info,
                      struct op_code_struct **opr)
                      struct op_code_struct **opr)
{
{
  unsigned char       ibytes[4];
  unsigned char       ibytes[4];
  int                 status;
  int                 status;
  struct op_code_struct * op;
  struct op_code_struct * op;
  unsigned long inst;
  unsigned long inst;
 
 
  status = info->read_memory_func (memaddr, ibytes, 4, info);
  status = info->read_memory_func (memaddr, ibytes, 4, info);
 
 
  if (status != 0)
  if (status != 0)
    {
    {
      info->memory_error_func (status, memaddr, info);
      info->memory_error_func (status, memaddr, info);
      return 0;
      return 0;
    }
    }
 
 
  if (info->endian == BFD_ENDIAN_BIG)
  if (info->endian == BFD_ENDIAN_BIG)
    inst = (ibytes[0] << 24) | (ibytes[1] << 16) | (ibytes[2] << 8) | ibytes[3];
    inst = (ibytes[0] << 24) | (ibytes[1] << 16) | (ibytes[2] << 8) | ibytes[3];
  else if (info->endian == BFD_ENDIAN_LITTLE)
  else if (info->endian == BFD_ENDIAN_LITTLE)
    inst = (ibytes[3] << 24) | (ibytes[2] << 16) | (ibytes[1] << 8) | ibytes[0];
    inst = (ibytes[3] << 24) | (ibytes[2] << 16) | (ibytes[1] << 8) | ibytes[0];
  else
  else
    abort ();
    abort ();
 
 
  /* Just a linear search of the table.  */
  /* Just a linear search of the table.  */
  for (op = opcodes; op->name != 0; op ++)
  for (op = opcodes; op->name != 0; op ++)
    if (op->bit_sequence == (inst & op->opcode_mask))
    if (op->bit_sequence == (inst & op->opcode_mask))
      break;
      break;
 
 
  *opr = op;
  *opr = op;
  return inst;
  return inst;
}
}
 
 
 
 
int
int
print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info)
print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info)
{
{
  fprintf_ftype       print_func = info->fprintf_func;
  fprintf_ftype       print_func = info->fprintf_func;
  void *              stream = info->stream;
  void *              stream = info->stream;
  unsigned long       inst, prev_inst;
  unsigned long       inst, prev_inst;
  struct op_code_struct * op, *pop;
  struct op_code_struct * op, *pop;
  int                 immval = 0;
  int                 immval = 0;
  bfd_boolean         immfound = FALSE;
  bfd_boolean         immfound = FALSE;
  static bfd_vma      prev_insn_addr = -1; /* Init the prev insn addr.  */
  static bfd_vma      prev_insn_addr = -1; /* Init the prev insn addr.  */
  static int          prev_insn_vma = -1;  /* Init the prev insn vma.  */
  static int          prev_insn_vma = -1;  /* Init the prev insn vma.  */
  int                 curr_insn_vma = info->buffer_vma;
  int                 curr_insn_vma = info->buffer_vma;
 
 
  info->bytes_per_chunk = 4;
  info->bytes_per_chunk = 4;
 
 
  inst = read_insn_microblaze (memaddr, info, &op);
  inst = read_insn_microblaze (memaddr, info, &op);
  if (inst == 0)
  if (inst == 0)
    return -1;
    return -1;
 
 
  if (prev_insn_vma == curr_insn_vma)
  if (prev_insn_vma == curr_insn_vma)
    {
    {
      if (memaddr-(info->bytes_per_chunk) == prev_insn_addr)
      if (memaddr-(info->bytes_per_chunk) == prev_insn_addr)
        {
        {
          prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop);
          prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop);
          if (prev_inst == 0)
          if (prev_inst == 0)
            return -1;
            return -1;
          if (pop->instr == imm)
          if (pop->instr == imm)
            {
            {
              immval = (get_int_field_imm (prev_inst) << 16) & 0xffff0000;
              immval = (get_int_field_imm (prev_inst) << 16) & 0xffff0000;
              immfound = TRUE;
              immfound = TRUE;
            }
            }
          else
          else
            {
            {
              immval = 0;
              immval = 0;
              immfound = FALSE;
              immfound = FALSE;
            }
            }
        }
        }
    }
    }
 
 
  /* Make curr insn as prev insn.  */
  /* Make curr insn as prev insn.  */
  prev_insn_addr = memaddr;
  prev_insn_addr = memaddr;
  prev_insn_vma = curr_insn_vma;
  prev_insn_vma = curr_insn_vma;
 
 
  if (op->name == NULL)
  if (op->name == NULL)
    print_func (stream, ".short 0x%04x", inst);
    print_func (stream, ".short 0x%04x", inst);
  else
  else
    {
    {
      print_func (stream, "%s", op->name);
      print_func (stream, "%s", op->name);
 
 
      switch (op->inst_type)
      switch (op->inst_type)
        {
        {
        case INST_TYPE_RD_R1_R2:
        case INST_TYPE_RD_R1_R2:
          print_func (stream, "\t%s, %s, %s", get_field_rd (inst),
          print_func (stream, "\t%s, %s, %s", get_field_rd (inst),
                   get_field_r1(inst), get_field_r2 (inst));
                   get_field_r1(inst), get_field_r2 (inst));
          break;
          break;
        case INST_TYPE_RD_R1_IMM:
        case INST_TYPE_RD_R1_IMM:
          print_func (stream, "\t%s, %s, %s", get_field_rd (inst),
          print_func (stream, "\t%s, %s, %s", get_field_rd (inst),
                   get_field_r1(inst), get_field_imm (inst));
                   get_field_r1(inst), get_field_imm (inst));
          if (info->print_address_func && get_int_field_r1 (inst) == 0
          if (info->print_address_func && get_int_field_r1 (inst) == 0
              && info->symbol_at_address_func)
              && info->symbol_at_address_func)
            {
            {
              if (immfound)
              if (immfound)
                immval |= (get_int_field_imm (inst) & 0x0000ffff);
                immval |= (get_int_field_imm (inst) & 0x0000ffff);
              else
              else
                {
                {
                  immval = get_int_field_imm (inst);
                  immval = get_int_field_imm (inst);
                  if (immval & 0x8000)
                  if (immval & 0x8000)
                    immval |= 0xFFFF0000;
                    immval |= 0xFFFF0000;
                }
                }
              if (immval > 0 && info->symbol_at_address_func (immval, info))
              if (immval > 0 && info->symbol_at_address_func (immval, info))
                {
                {
                  print_func (stream, "\t// ");
                  print_func (stream, "\t// ");
                  info->print_address_func (immval, info);
                  info->print_address_func (immval, info);
                }
                }
            }
            }
          break;
          break;
        case INST_TYPE_RD_R1_IMM5:
        case INST_TYPE_RD_R1_IMM5:
          print_func (stream, "\t%s, %s, %s", get_field_rd (inst),
          print_func (stream, "\t%s, %s, %s", get_field_rd (inst),
                   get_field_r1(inst), get_field_imm5 (inst));
                   get_field_r1(inst), get_field_imm5 (inst));
          break;
          break;
        case INST_TYPE_RD_RFSL:
        case INST_TYPE_RD_RFSL:
          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_rfsl (inst));
          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_rfsl (inst));
          break;
          break;
        case INST_TYPE_R1_RFSL:
        case INST_TYPE_R1_RFSL:
          print_func (stream, "\t%s, %s", get_field_r1 (inst), get_field_rfsl (inst));
          print_func (stream, "\t%s, %s", get_field_r1 (inst), get_field_rfsl (inst));
          break;
          break;
        case INST_TYPE_RD_SPECIAL:
        case INST_TYPE_RD_SPECIAL:
          print_func (stream, "\t%s, %s", get_field_rd (inst),
          print_func (stream, "\t%s, %s", get_field_rd (inst),
                   get_field_special (inst, op));
                   get_field_special (inst, op));
          break;
          break;
        case INST_TYPE_SPECIAL_R1:
        case INST_TYPE_SPECIAL_R1:
          print_func (stream, "\t%s, %s", get_field_special (inst, op),
          print_func (stream, "\t%s, %s", get_field_special (inst, op),
                   get_field_r1(inst));
                   get_field_r1(inst));
          break;
          break;
        case INST_TYPE_RD_R1:
        case INST_TYPE_RD_R1:
          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_r1 (inst));
          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_r1 (inst));
          break;
          break;
        case INST_TYPE_R1_R2:
        case INST_TYPE_R1_R2:
          print_func (stream, "\t%s, %s", get_field_r1 (inst), get_field_r2 (inst));
          print_func (stream, "\t%s, %s", get_field_r1 (inst), get_field_r2 (inst));
          break;
          break;
        case INST_TYPE_R1_IMM:
        case INST_TYPE_R1_IMM:
          print_func (stream, "\t%s, %s", get_field_r1 (inst), get_field_imm (inst));
          print_func (stream, "\t%s, %s", get_field_r1 (inst), get_field_imm (inst));
          /* The non-pc relative instructions are returns, which shouldn't
          /* The non-pc relative instructions are returns, which shouldn't
             have a label printed.  */
             have a label printed.  */
          if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET
          if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET
              && info->symbol_at_address_func)
              && info->symbol_at_address_func)
            {
            {
              if (immfound)
              if (immfound)
                immval |= (get_int_field_imm (inst) & 0x0000ffff);
                immval |= (get_int_field_imm (inst) & 0x0000ffff);
              else
              else
                {
                {
                  immval = get_int_field_imm (inst);
                  immval = get_int_field_imm (inst);
                  if (immval & 0x8000)
                  if (immval & 0x8000)
                    immval |= 0xFFFF0000;
                    immval |= 0xFFFF0000;
                }
                }
              immval += memaddr;
              immval += memaddr;
              if (immval > 0 && info->symbol_at_address_func (immval, info))
              if (immval > 0 && info->symbol_at_address_func (immval, info))
                {
                {
                  print_func (stream, "\t// ");
                  print_func (stream, "\t// ");
                  info->print_address_func (immval, info);
                  info->print_address_func (immval, info);
                }
                }
              else
              else
                {
                {
                  print_func (stream, "\t\t// ");
                  print_func (stream, "\t\t// ");
                  print_func (stream, "%x", immval);
                  print_func (stream, "%x", immval);
                }
                }
            }
            }
          break;
          break;
        case INST_TYPE_RD_IMM:
        case INST_TYPE_RD_IMM:
          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_imm (inst));
          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_imm (inst));
          if (info->print_address_func && info->symbol_at_address_func)
          if (info->print_address_func && info->symbol_at_address_func)
            {
            {
            if (immfound)
            if (immfound)
              immval |= (get_int_field_imm (inst) & 0x0000ffff);
              immval |= (get_int_field_imm (inst) & 0x0000ffff);
            else
            else
              {
              {
                immval = get_int_field_imm (inst);
                immval = get_int_field_imm (inst);
                if (immval & 0x8000)
                if (immval & 0x8000)
                  immval |= 0xFFFF0000;
                  immval |= 0xFFFF0000;
              }
              }
            if (op->inst_offset_type == INST_PC_OFFSET)
            if (op->inst_offset_type == INST_PC_OFFSET)
              immval += (int) memaddr;
              immval += (int) memaddr;
            if (info->symbol_at_address_func (immval, info))
            if (info->symbol_at_address_func (immval, info))
              {
              {
                print_func (stream, "\t// ");
                print_func (stream, "\t// ");
                info->print_address_func (immval, info);
                info->print_address_func (immval, info);
              }
              }
            }
            }
          break;
          break;
        case INST_TYPE_IMM:
        case INST_TYPE_IMM:
          print_func (stream, "\t%s", get_field_imm (inst));
          print_func (stream, "\t%s", get_field_imm (inst));
          if (info->print_address_func && info->symbol_at_address_func
          if (info->print_address_func && info->symbol_at_address_func
              && op->instr != imm)
              && op->instr != imm)
            {
            {
              if (immfound)
              if (immfound)
                immval |= (get_int_field_imm (inst) & 0x0000ffff);
                immval |= (get_int_field_imm (inst) & 0x0000ffff);
              else
              else
                {
                {
                  immval = get_int_field_imm (inst);
                  immval = get_int_field_imm (inst);
                  if (immval & 0x8000)
                  if (immval & 0x8000)
                    immval |= 0xFFFF0000;
                    immval |= 0xFFFF0000;
                }
                }
              if (op->inst_offset_type == INST_PC_OFFSET)
              if (op->inst_offset_type == INST_PC_OFFSET)
                immval += (int) memaddr;
                immval += (int) memaddr;
              if (immval > 0 && info->symbol_at_address_func (immval, info))
              if (immval > 0 && info->symbol_at_address_func (immval, info))
                {
                {
                  print_func (stream, "\t// ");
                  print_func (stream, "\t// ");
                  info->print_address_func (immval, info);
                  info->print_address_func (immval, info);
                }
                }
              else if (op->inst_offset_type == INST_PC_OFFSET)
              else if (op->inst_offset_type == INST_PC_OFFSET)
                {
                {
                  print_func (stream, "\t\t// ");
                  print_func (stream, "\t\t// ");
                  print_func (stream, "%x", immval);
                  print_func (stream, "%x", immval);
                }
                }
            }
            }
          break;
          break;
        case INST_TYPE_RD_R2:
        case INST_TYPE_RD_R2:
          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_r2 (inst));
          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_r2 (inst));
          break;
          break;
        case INST_TYPE_R2:
        case INST_TYPE_R2:
          print_func (stream, "\t%s", get_field_r2 (inst));
          print_func (stream, "\t%s", get_field_r2 (inst));
          break;
          break;
        case INST_TYPE_R1:
        case INST_TYPE_R1:
          print_func (stream, "\t%s", get_field_r1 (inst));
          print_func (stream, "\t%s", get_field_r1 (inst));
          break;
          break;
        case INST_TYPE_RD_R1_SPECIAL:
        case INST_TYPE_RD_R1_SPECIAL:
          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_r2 (inst));
          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_r2 (inst));
          break;
          break;
        case INST_TYPE_RD_IMM15:
        case INST_TYPE_RD_IMM15:
          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_imm15 (inst));
          print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_imm15 (inst));
          break;
          break;
        /* For tuqula instruction */
        /* For tuqula instruction */
        case INST_TYPE_RD:
        case INST_TYPE_RD:
          print_func (stream, "\t%s", get_field_rd (inst));
          print_func (stream, "\t%s", get_field_rd (inst));
          break;
          break;
        case INST_TYPE_RFSL:
        case INST_TYPE_RFSL:
          print_func (stream, "\t%s", get_field_rfsl (inst));
          print_func (stream, "\t%s", get_field_rfsl (inst));
          break;
          break;
        default:
        default:
          /* If the disassembler lags the instruction set.  */
          /* If the disassembler lags the instruction set.  */
          print_func (stream, "\tundecoded operands, inst is 0x%04x", inst);
          print_func (stream, "\tundecoded operands, inst is 0x%04x", inst);
          break;
          break;
        }
        }
    }
    }
 
 
  /* Say how many bytes we consumed.  */
  /* Say how many bytes we consumed.  */
  return 4;
  return 4;
}
}
 
 
enum microblaze_instr
enum microblaze_instr
get_insn_microblaze (long inst,
get_insn_microblaze (long inst,
                     bfd_boolean *isunsignedimm,
                     bfd_boolean *isunsignedimm,
                     enum microblaze_instr_type *insn_type,
                     enum microblaze_instr_type *insn_type,
                     short *delay_slots)
                     short *delay_slots)
{
{
  struct op_code_struct * op;
  struct op_code_struct * op;
  *isunsignedimm = FALSE;
  *isunsignedimm = FALSE;
 
 
  /* Just a linear search of the table.  */
  /* Just a linear search of the table.  */
  for (op = opcodes; op->name != 0; op ++)
  for (op = opcodes; op->name != 0; op ++)
    if (op->bit_sequence == (inst & op->opcode_mask))
    if (op->bit_sequence == (inst & op->opcode_mask))
      break;
      break;
 
 
  if (op->name == 0)
  if (op->name == 0)
    return invalid_inst;
    return invalid_inst;
  else
  else
    {
    {
      *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM);
      *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM);
      *insn_type = op->instr_type;
      *insn_type = op->instr_type;
      *delay_slots = op->delay_slots;
      *delay_slots = op->delay_slots;
      return op->instr;
      return op->instr;
    }
    }
}
}
 
 
enum microblaze_instr
enum microblaze_instr
microblaze_decode_insn (long insn, int *rd, int *ra, int *rb, int *immed)
microblaze_decode_insn (long insn, int *rd, int *ra, int *rb, int *immed)
{
{
  enum microblaze_instr op;
  enum microblaze_instr op;
  bfd_boolean t1;
  bfd_boolean t1;
  enum microblaze_instr_type t2;
  enum microblaze_instr_type t2;
  short t3;
  short t3;
 
 
  op = get_insn_microblaze (insn, &t1, &t2, &t3);
  op = get_insn_microblaze (insn, &t1, &t2, &t3);
  *rd = (insn & RD_MASK) >> RD_LOW;
  *rd = (insn & RD_MASK) >> RD_LOW;
  *ra = (insn & RA_MASK) >> RA_LOW;
  *ra = (insn & RA_MASK) >> RA_LOW;
  *rb = (insn & RB_MASK) >> RB_LOW;
  *rb = (insn & RB_MASK) >> RB_LOW;
  t3 = (insn & IMM_MASK) >> IMM_LOW;
  t3 = (insn & IMM_MASK) >> IMM_LOW;
  *immed = (int) t3;
  *immed = (int) t3;
  return (op);
  return (op);
}
}
 
 
unsigned long
unsigned long
microblaze_get_target_address (long inst, bfd_boolean immfound, int immval,
microblaze_get_target_address (long inst, bfd_boolean immfound, int immval,
                               long pcval, long r1val, long r2val,
                               long pcval, long r1val, long r2val,
                               bfd_boolean *targetvalid,
                               bfd_boolean *targetvalid,
                               bfd_boolean *unconditionalbranch)
                               bfd_boolean *unconditionalbranch)
{
{
  struct op_code_struct * op;
  struct op_code_struct * op;
  long targetaddr = 0;
  long targetaddr = 0;
 
 
  *unconditionalbranch = FALSE;
  *unconditionalbranch = FALSE;
  /* Just a linear search of the table.  */
  /* Just a linear search of the table.  */
  for (op = opcodes; op->name != 0; op ++)
  for (op = opcodes; op->name != 0; op ++)
    if (op->bit_sequence == (inst & op->opcode_mask))
    if (op->bit_sequence == (inst & op->opcode_mask))
      break;
      break;
 
 
  if (op->name == 0)
  if (op->name == 0)
    {
    {
      *targetvalid = FALSE;
      *targetvalid = FALSE;
    }
    }
  else if (op->instr_type == branch_inst)
  else if (op->instr_type == branch_inst)
    {
    {
      switch (op->inst_type)
      switch (op->inst_type)
        {
        {
        case INST_TYPE_R2:
        case INST_TYPE_R2:
          *unconditionalbranch = TRUE;
          *unconditionalbranch = TRUE;
        /* Fall through.  */
        /* Fall through.  */
        case INST_TYPE_RD_R2:
        case INST_TYPE_RD_R2:
        case INST_TYPE_R1_R2:
        case INST_TYPE_R1_R2:
          targetaddr = r2val;
          targetaddr = r2val;
          *targetvalid = TRUE;
          *targetvalid = TRUE;
          if (op->inst_offset_type == INST_PC_OFFSET)
          if (op->inst_offset_type == INST_PC_OFFSET)
            targetaddr += pcval;
            targetaddr += pcval;
          break;
          break;
        case INST_TYPE_IMM:
        case INST_TYPE_IMM:
          *unconditionalbranch = TRUE;
          *unconditionalbranch = TRUE;
        /* Fall through.  */
        /* Fall through.  */
        case INST_TYPE_RD_IMM:
        case INST_TYPE_RD_IMM:
        case INST_TYPE_R1_IMM:
        case INST_TYPE_R1_IMM:
          if (immfound)
          if (immfound)
            {
            {
              targetaddr = (immval << 16) & 0xffff0000;
              targetaddr = (immval << 16) & 0xffff0000;
              targetaddr |= (get_int_field_imm (inst) & 0x0000ffff);
              targetaddr |= (get_int_field_imm (inst) & 0x0000ffff);
            }
            }
          else
          else
            {
            {
              targetaddr = get_int_field_imm (inst);
              targetaddr = get_int_field_imm (inst);
              if (targetaddr & 0x8000)
              if (targetaddr & 0x8000)
                targetaddr |= 0xFFFF0000;
                targetaddr |= 0xFFFF0000;
            }
            }
          if (op->inst_offset_type == INST_PC_OFFSET)
          if (op->inst_offset_type == INST_PC_OFFSET)
            targetaddr += pcval;
            targetaddr += pcval;
          *targetvalid = TRUE;
          *targetvalid = TRUE;
          break;
          break;
        default:
        default:
          *targetvalid = FALSE;
          *targetvalid = FALSE;
          break;
          break;
        }
        }
    }
    }
  else if (op->instr_type == return_inst)
  else if (op->instr_type == return_inst)
    {
    {
      if (immfound)
      if (immfound)
        {
        {
          targetaddr = (immval << 16) & 0xffff0000;
          targetaddr = (immval << 16) & 0xffff0000;
          targetaddr |= (get_int_field_imm (inst) & 0x0000ffff);
          targetaddr |= (get_int_field_imm (inst) & 0x0000ffff);
        }
        }
      else
      else
        {
        {
          targetaddr = get_int_field_imm (inst);
          targetaddr = get_int_field_imm (inst);
          if (targetaddr & 0x8000)
          if (targetaddr & 0x8000)
            targetaddr |= 0xFFFF0000;
            targetaddr |= 0xFFFF0000;
        }
        }
      targetaddr += r1val;
      targetaddr += r1val;
      *targetvalid = TRUE;
      *targetvalid = TRUE;
    }
    }
  else
  else
    *targetvalid = FALSE;
    *targetvalid = FALSE;
  return targetaddr;
  return targetaddr;
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.