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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-6.8/] [opcodes/] [or32-dis.c] - Diff between revs 157 and 225

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 157 Rev 225
Line 1... Line 1...
/* Instruction printing code for the OpenRISC 1000
/* Instruction printing code for the OpenRISC 1000
 
 
   Copyright (C) 2002, 2005, 2007 Free Software Foundation, Inc.
   Copyright (C) 2002, 2005, 2007 Free Software Foundation, Inc.
   Copyright (C) 2008 Embecosm Limited
 
 
 
   Contributed by Damjan Lampret <lampret@opencores.org>.
   Contributed by Damjan Lampret <lampret@opencores.org>.
   Modified from a29k port.
   Modified from a29k port.
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
 
 
   This file is part of the GNU opcodes library.
   This file is part of the GNU opcodes library.
 
 
   This program is free software; you can redistribute it and/or modify it
   This library is free software; you can redistribute it and/or modify
   under the terms of the GNU General Public License as published by the Free
   it under the terms of the GNU General Public License as published by
   Software Foundation; either version 3 of the License, or (at your option)
   the Free Software Foundation; either version 3, or (at your option)
   any later version.
   any later version.
 
 
   This program 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 or
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
   more details.
   License for more details.
 
 
   You should have received a copy of the GNU General Public License along
   You should have received a copy of the GNU General Public License
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   along with this program; if not, write to the Free Software
 
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
/*-----------------------------------------------------------------------------
   MA 02110-1301, USA.  */
   This version for the OpenRISC 1000 architecture is an update by Jeremy
 
   Bennett for GDB 6.8. All code converted to ANSI C style and in general to
 
   GDB format.
 
 
 
   Signed immediate constants are printed as such (the old version printed
 
   them as unsigned hex). Where appropriate symbolic names are used for
 
   immediate branch and jump targets.
 
   --------------------------------------------------------------------------*/
 
 
 
 
#define DEBUG 0
 
 
#include "dis-asm.h"
#include "dis-asm.h"
#include "opcode/or32.h"
#include "opcode/or32.h"
#include "safe-ctype.h"
#include "safe-ctype.h"
#include <string.h>
#include <string.h>
#include <stdlib.h>
#include <stdlib.h>
 
 
 
#define EXTEND28(x) ((x) & (unsigned long) 0x08000000 ? ((x) | (unsigned long) 0xf0000000) : ((x)))
 
 
#define EXTEND29(x) ((x) & (unsigned long) 0x10000000 ? ((x) | (unsigned long) 0xf0000000) : ((x)))
/* Now find the four bytes of INSN_CH and put them in *INSN.  */
 
 
/* A cop out - this is in defs.h, but including that from the main GDB
 
   component would be a pain. Really the dependency on CORE_ADDR ought to be
 
   added to the or1k-tdep.c, rather than being here. Something for the
 
   future. */
 
typedef bfd_vma CORE_ADDR;
 
 
 
 
 
/* Function to look up an address as a symbol. Found in the GDB area */
 
extern int
 
build_address_symbolic (CORE_ADDR   addr,
 
                        int         do_demangle,
 
                        char      **name,
 
                        int        *offset,
 
                        char      **filename,
 
                        int        *line,
 
                        int        *unmapped);
 
 
 
 
 
/*!----------------------------------------------------------------------------
 
   Map 4 bytes of instruction into one 32-bit word for big-endian target
 
 
 
   @param[in]  insn_ch  The 4 bytes of the instruction
 
   @param[out] insn     The 32-bit word
 
   --------------------------------------------------------------------------*/
 
 
 
static void
static void
find_bytes_big (unsigned char *insn_ch,
find_bytes_big (unsigned char *insn_ch, unsigned long *insn)
                unsigned long *insn)
 
{
{
  *insn =
  *insn =
    ((unsigned long) insn_ch[0] << 24) +
    ((unsigned long) insn_ch[0] << 24) +
    ((unsigned long) insn_ch[1] << 16) +
    ((unsigned long) insn_ch[1] << 16) +
    ((unsigned long) insn_ch[2] << 8) +
    ((unsigned long) insn_ch[2] << 8) +
    ((unsigned long) insn_ch[3]);
    ((unsigned long) insn_ch[3]);
 
#if DEBUG
}       /* find_bytes_big() */
  printf ("find_bytes_big3: %x\n", *insn);
 
#endif
 
}
/*!----------------------------------------------------------------------------
 
   Map 4 bytes of instruction into one 32-bit word for little-endian target
 
 
 
   @param[in]  insn_ch  The 4 bytes of the instruction
 
   @param[out] insn     The 32-bit word
 
   --------------------------------------------------------------------------*/
 
 
 
static void
static void
find_bytes_little (unsigned char *insn_ch,
find_bytes_little (unsigned char *insn_ch, unsigned long *insn)
                   unsigned long *insn)
 
{
{
  *insn =
  *insn =
    ((unsigned long) insn_ch[3] << 24) +
    ((unsigned long) insn_ch[3] << 24) +
    ((unsigned long) insn_ch[2] << 16) +
    ((unsigned long) insn_ch[2] << 16) +
    ((unsigned long) insn_ch[1] << 8) +
    ((unsigned long) insn_ch[1] << 8) +
    ((unsigned long) insn_ch[0]);
    ((unsigned long) insn_ch[0]);
 
}
 
 
}       /* find_bytes_little() */
typedef void (*find_byte_func_type) (unsigned char *, unsigned long *);
 
 
 
 
/*!----------------------------------------------------------------------------
 
   Extract an instruction field
 
 
 
   @param[in] param_ch     The character identifying the field
 
   @param[in] enc_initial  A string with 1 char for each bit in the
 
                           instruction, the char indicating the field the bit
 
                           belongs to
 
   @param[in] insn         The instruction
 
 
 
   @return  The value of the field
 
   --------------------------------------------------------------------------*/
 
 
 
static unsigned long
static unsigned long
or32_extract (char               param_ch,
or32_extract (char param_ch, char *enc_initial, unsigned long insn)
              char              *enc_initial,
 
              unsigned long int  insn)
 
{
{
  char              *enc;
  char              *enc;
  unsigned long int  ret       = 0;
  unsigned long ret = 0;
  int                opc_pos   = 0;
  int                opc_pos   = 0;
  int                param_pos = 0;
  int                param_pos = 0;
 
 
  for (enc = enc_initial; *enc != '\0'; enc++)
  for (enc = enc_initial; *enc != '\0'; enc++)
    {
 
      if (*enc == param_ch)
      if (*enc == param_ch)
        {
        {
          if ((enc - 2    >= enc_initial) &&
        if (enc - 2 >= enc_initial && (*(enc - 2) == '0') && (*(enc - 1) == 'x'))
              (*(enc - 2) == '0')         &&
 
              (*(enc - 1) == 'x'))
 
            {
 
              continue;
              continue;
            }
 
          else
          else
            {
 
              param_pos++;
              param_pos++;
            }
            }
        }
 
    }
 
 
 
 
#if DEBUG
 
  printf ("or32_extract: %c %x ", param_ch, param_pos);
 
#endif
  opc_pos = 32;
  opc_pos = 32;
 
 
  for (enc = enc_initial; *enc != '\0'; )
  for (enc = enc_initial; *enc != '\0'; )
    {
 
      if ((*enc == '0') && (*(enc + 1) == 'x'))
      if ((*enc == '0') && (*(enc + 1) == 'x'))
        {
        {
          opc_pos -= 4;
          opc_pos -= 4;
 
 
          if ((param_ch == '0') || (param_ch == '1'))
          if ((param_ch == '0') || (param_ch == '1'))
            {
            {
              unsigned long tmp = strtoul (enc, NULL, 16);
              unsigned long tmp = strtoul (enc, NULL, 16);
 
#if DEBUG
              if (param_ch == '0') {
            printf (" enc=%s, tmp=%x ", enc, tmp);
 
#endif
 
            if (param_ch == '0')
                tmp = 15 - tmp;
                tmp = 15 - tmp;
              }
 
 
 
              ret |= tmp << opc_pos;
              ret |= tmp << opc_pos;
            }
            }
 
 
          enc += 3;
          enc += 3;
        }
        }
      else if ((*enc == '0') || (*enc == '1'))
      else if ((*enc == '0') || (*enc == '1'))
        {
        {
          opc_pos--;
          opc_pos--;
 
        if (param_ch == *enc)
          if (param_ch == *enc) {
 
            ret |= 1 << opc_pos;
            ret |= 1 << opc_pos;
          }
 
 
 
          enc++;
          enc++;
        }
        }
      else if (*enc == param_ch)
      else if (*enc == param_ch)
        {
        {
          opc_pos--;
          opc_pos--;
          param_pos--;
          param_pos--;
 
#if DEBUG
 
        printf ("\n  ret=%x opc_pos=%x, param_pos=%x\n", ret, opc_pos, param_pos);
 
#endif
          ret += ((insn >> opc_pos) & 0x1) << param_pos;
          ret += ((insn >> opc_pos) & 0x1) << param_pos;
 
 
          if (!param_pos               &&
        if (!param_pos
              letter_signed (param_ch) &&
            && letter_signed (param_ch)
              ret >> (letter_range (param_ch) - 1))
            && ret >> (letter_range (param_ch) - 1))
            {
          {
 
#if DEBUG
 
            printf ("\n  ret=%x opc_pos=%x, param_pos=%x\n",
 
                    ret, opc_pos, param_pos);
 
#endif
              ret |= 0xffffffff << letter_range(param_ch);
              ret |= 0xffffffff << letter_range(param_ch);
 
#if DEBUG
 
            printf ("\n  after conversion to signed: ret=%x\n", ret);
 
#endif
            }
            }
          enc++;
          enc++;
        }
        }
      else if (ISALPHA (*enc))
      else if (ISALPHA (*enc))
        {
        {
Line 193... Line 136...
        {
        {
          opc_pos--;
          opc_pos--;
          enc++;
          enc++;
        }
        }
      else
      else
        {
 
          enc++;
          enc++;
        }
 
    }
 
 
 
 
#if DEBUG
 
  printf ("ret=%x\n", ret);
 
#endif
  return ret;
  return ret;
 
}
}       /* or32_extract() */
 
 
 
 
 
/*!----------------------------------------------------------------------------
 
   Test if an instruction matches an encoding
 
 
 
   @param[in] insn      The instruction
 
   @param[in] encoding  The encoding
 
 
 
   @return  1 (true) if they match, 0 otherwise
 
   --------------------------------------------------------------------------*/
 
 
 
static int
static int
or32_opcode_match (unsigned long insn, char *encoding)
or32_opcode_match (unsigned long insn, char *encoding)
{
{
  unsigned long ones, zeros;
  unsigned long ones, zeros;
 
 
 
#if DEBUG
 
  printf ("or32_opcode_match: %.8lx\n", insn);
 
#endif    
  ones  = or32_extract ('1', encoding, insn);
  ones  = or32_extract ('1', encoding, insn);
  zeros = or32_extract ('0', encoding, insn);
  zeros = or32_extract ('0', encoding, insn);
 
 
 
  // Added 090430 - jb - fixed problem where upper 4 bytes of a 64-bit long weren't getting setup properly for comparison
 
  // As a result, instructions weren't getting decoded properly
 
  insn &= 0xffffffff;
 
  ones &= 0xffffffff;
 
  zeros &= 0xffffffff;
 
 
 
#if DEBUG
 
  printf ("ones: %x \n", ones);
 
  printf ("zeros: %x \n", zeros);
 
#endif
  if ((insn & ones) != ones)
  if ((insn & ones) != ones)
    {
    {
 
#if DEBUG
 
      printf ("ret1\n");
 
#endif
      return 0;
      return 0;
    }
    }
 
 
  if ((~insn & zeros) != zeros)
  if ((~insn & zeros) != zeros)
    {
    {
 
#if DEBUG
 
      printf ("ret2\n");
 
#endif
      return 0;
      return 0;
    }
    }
 
 
 
#if DEBUG
 
  printf ("ret3\n");
 
#endif
  return 1;
  return 1;
 
}
 
 
}       /* or32_opcode_match() */
/* Print register to INFO->STREAM. Used only by print_insn.  */
 
 
 
 
/*!----------------------------------------------------------------------------
 
   Print register to INFO->STREAM.
 
 
 
   Used only by print_insn.
 
 
 
   @param[in] param_ch  The character encoding the field of interest
 
   @param[in] encoding  The encoding
 
   @param[in] insn      The instruction
 
   @param[in] info      Info about the disassembly, in particular with the
 
                        stream to write to.
 
   --------------------------------------------------------------------------*/
 
 
 
static void
static void
or32_print_register (char param_ch,
or32_print_register (char param_ch,
                     char *encoding,
                     char *encoding,
                     unsigned long insn,
                     unsigned long insn,
                     struct disassemble_info *info)
                     struct disassemble_info *info)
{
{
  int regnum = or32_extract (param_ch, encoding, insn);
  int regnum = or32_extract (param_ch, encoding, insn);
 
 
  switch (param_ch)
#if DEBUG
    {
  printf ("or32_print_register: %c, %s, %x\n", param_ch, encoding, insn);
    case 'A':
#endif  
    case 'B':
  if (param_ch == 'A')
    case 'D':
 
      (*info->fprintf_func) (info->stream, "r%d", regnum);
      (*info->fprintf_func) (info->stream, "r%d", regnum);
      break;
  else if (param_ch == 'B')
 
    (*info->fprintf_func) (info->stream, "r%d", regnum);
    default:
  else if (param_ch == 'D')
      if (regnum < 16)
    (*info->fprintf_func) (info->stream, "r%d", regnum);
        {
  else if (regnum < 16)
          (*info->fprintf_func) (info->stream, "r%d", regnum);
          (*info->fprintf_func) (info->stream, "r%d", regnum);
        }
 
      else if (regnum < 32)
      else if (regnum < 32)
        {
 
          (*info->fprintf_func) (info->stream, "r%d", regnum-16);
          (*info->fprintf_func) (info->stream, "r%d", regnum-16);
        }
 
      else
      else
        {
 
          (*info->fprintf_func) (info->stream, "X%d", regnum);
          (*info->fprintf_func) (info->stream, "X%d", regnum);
        }
        }
    }
 
}       /* or32_print_register() */
 
 
 
 
 
 
 
/*!----------------------------------------------------------------------------
 
   Print immediate to INFO->STREAM.
 
 
 
   Used only by print_insn.
 
 
 
   Fixed in GDB 6.8 to print signed immediate fields correctly and to set the
 
   target fields of jump and branch to symbols if possible.
 
 
 
   @param[in] memaddr   Address of this instruction
 
   @param[in] param_ch  The character encoding the field of interest
 
   @param[in] encoding  The encoding
 
   @param[in] insn      The instruction
 
   @param[in] info      Info about the disassembly, in particular with the
 
                        stream to write to.
 
   --------------------------------------------------------------------------*/
 
 
 
/* Print immediate to INFO->STREAM. Used only by print_insn.  */
/* Print immediate to INFO->STREAM. Used only by print_insn.  */
 
 
static void
static void
or32_print_immediate( bfd_vma                  memaddr,
or32_print_immediate (char param_ch,
                      char                     param_ch,
 
                      char                    *encoding,
                      char                    *encoding,
                      unsigned long            insn,
                      unsigned long            insn,
                      struct disassemble_info *info)
                      struct disassemble_info *info)
{
{
  int imm = or32_extract(param_ch, encoding, insn);
  int imm = or32_extract(param_ch, encoding, insn);
 
 
  if ('N' == param_ch)
  if (letter_signed(param_ch))
    {
 
      CORE_ADDR  target_addr = (CORE_ADDR)(memaddr + (4 * imm));
 
      char      *name        = NULL;
 
      char      *filename    = NULL;
 
      int        unmapped    = 0;
 
      int        offset      = 0;
 
      int        line        = 0;
 
 
 
      if( 0 == build_address_symbolic( target_addr, 1, &name, &offset,
 
                                       &filename, &line, &unmapped ))
 
        {
 
          (*info->fprintf_func) (info->stream, "<" );
 
 
 
          if( unmapped )
 
            {
 
              (*info->fprintf_func) (info->stream, "*");
 
            }
 
 
 
          (*info->fprintf_func) (info->stream, "%s", name);
 
 
 
          if( offset )
 
            {
 
              (*info->fprintf_func) (info->stream, "+%d", offset);
 
            }
 
 
 
          (*info->fprintf_func) (info->stream, ">" );
 
        }
 
      else
 
        {
 
          (*info->fprintf_func) (info->stream, "0x%x", imm);
          (*info->fprintf_func) (info->stream, "0x%x", imm);
        }
/*    (*info->fprintf_func) (info->stream, "%d", imm); */
    }
 
  else if (letter_signed(param_ch))
 
    {
 
      (*info->fprintf_func) (info->stream, "%d", imm);
 
    }
 
  else
  else
    {
 
      (*info->fprintf_func) (info->stream, "0x%x", imm);
      (*info->fprintf_func) (info->stream, "0x%x", imm);
    }
    }
}       /* or32_print_immediate() */
 
 
 
 
 
/*!----------------------------------------------------------------------------
 
   Print one instruction
 
 
 
   Print one instruction from MEMADDR on INFO->STREAM.
 
 
 
   @param[in] memaddr   Address of the instruction to print
 
   @param[in] info      Info about the disassembly, in particular with the
 
                        stream to write to.
 
 
 
   @return   The size of the instruction (always 4 on or32).
/* Print one instruction from MEMADDR on INFO->STREAM.
   --------------------------------------------------------------------------*/
   Return the size of the instruction (always 4 on or32).  */
 
 
static int
static int
print_insn (bfd_vma                  memaddr,
print_insn (bfd_vma memaddr, struct disassemble_info *info)
            struct disassemble_info *info)
 
{
{
  /* The raw instruction.  */
  /* The raw instruction.  */
  unsigned char insn_ch[4];
  unsigned char insn_ch[4];
  /* Address. Will be sign extened 27-bit.  */
  /* Address. Will be sign extened 27-bit.  */
  unsigned long addr;
  unsigned long addr;
  /* The four bytes of the instruction.  */
  /* The four bytes of the instruction.  */
  unsigned long insn;
  unsigned long insn;
 
 
  typedef void (*find_byte_func_type) (unsigned char *, unsigned long *);
 
 
 
  find_byte_func_type find_byte_func = (find_byte_func_type) info->private_data;
  find_byte_func_type find_byte_func = (find_byte_func_type) info->private_data;
  struct or32_opcode const *opcode;
  struct or32_opcode const *opcode;
 
 
 
  {
  int status =
  int status =
    (*info->read_memory_func) (memaddr, (bfd_byte *) &insn_ch[0], 4, info);
    (*info->read_memory_func) (memaddr, (bfd_byte *) &insn_ch[0], 4, info);
 
 
  if (status != 0)
  if (status != 0)
    {
    {
      (*info->memory_error_func) (status, memaddr, info);
      (*info->memory_error_func) (status, memaddr, info);
      return -1;
      return -1;
    }
    }
 
  }
 
 
  (*find_byte_func) (&insn_ch[0], &insn);
  (*find_byte_func) (&insn_ch[0], &insn);
 
 
  for (opcode = &or32_opcodes[0];
  for (opcode = &or32_opcodes[0];
       opcode < &or32_opcodes[or32_num_opcodes];
       opcode < &or32_opcodes[or32_num_opcodes];
Line 399... Line 267...
    {
    {
      if (or32_opcode_match (insn, opcode->encoding))
      if (or32_opcode_match (insn, opcode->encoding))
        {
        {
          char *s;
          char *s;
 
 
          (*info->fprintf_func) (info->stream, "%-8s ", opcode->name);
          (*info->fprintf_func) (info->stream, "%s ", opcode->name);
 
 
          for (s = opcode->args; *s != '\0'; ++s)
          for (s = opcode->args; *s != '\0'; ++s)
            {
            {
              switch (*s)
              switch (*s)
                {
                {
Line 412... Line 280...
 
 
                case 'r':
                case 'r':
                  or32_print_register (*++s, opcode->encoding, insn, info);
                  or32_print_register (*++s, opcode->encoding, insn, info);
                  break;
                  break;
 
 
                case 'X':
                case 'N':
                  addr = or32_extract ('X', opcode->encoding, insn) << 2;
                  addr = or32_extract ('N', opcode->encoding, insn) << 2;
 
 
                  /* Calulate the correct address.  XXX is this really correct
                  /* Calulate the correct address.  */
                     ??  */
                  addr = memaddr + EXTEND28 (addr);
                  addr = memaddr + EXTEND29 (addr);
 
 
 
                  (*info->print_address_func)
                  (*info->print_address_func)
                    (addr, info);
                    (addr, info);
                  break;
                  break;
 
 
                default:
                default:
                  if (strchr (opcode->encoding, *s))
                  if (strchr (opcode->encoding, *s))
                    {
                    or32_print_immediate (*s, opcode->encoding, insn, info);
                      or32_print_immediate (memaddr, *s, opcode->encoding,
 
                                            insn, info);
 
                    }
 
                  else
                  else
                    {
 
                      (*info->fprintf_func) (info->stream, "%c", *s);
                      (*info->fprintf_func) (info->stream, "%c", *s);
                    }
                    }
                }
                }
            }
 
 
 
          return 4;
          return 4;
        }
        }
    }
    }
 
 
  /* This used to be %8x for binutils.  */
  /* This used to be %8x for binutils.  */
  (*info->fprintf_func) (info->stream, ".word 0x%08lx", insn);
  (*info->fprintf_func)
 
    (info->stream, ".word 0x%08lx", insn);
  return 4;
  return 4;
 
}
 
 
}       /* print_insn() */
/* Disassemble a big-endian or32 instruction.  */
 
 
 
 
/*!----------------------------------------------------------------------------
 
   Disassemble a big-endian or32 instruction
 
 
 
   Print one instruction from MEMADDR on INFO->STREAM.
 
 
 
   @param[in] memaddr   Address of the instruction to print
 
   @param[in] info      Info about the disassembly, in particular with the
 
                        stream to write to.
 
 
 
   @return   The size of the instruction (always 4 on or32).
 
   --------------------------------------------------------------------------*/
 
 
 
int
int
print_insn_big_or32 (bfd_vma                  memaddr,
print_insn_big_or32 (bfd_vma memaddr, struct disassemble_info *info)
                     struct disassemble_info *info)
 
{
{
  info->private_data = find_bytes_big;
  info->private_data = find_bytes_big;
 
 
  return print_insn (memaddr, info);
  return print_insn (memaddr, info);
 
}
 
 
}       /* print_insn_big_or32() */
/* Disassemble a little-endian or32 instruction.  */
 
 
 
 
/*!----------------------------------------------------------------------------
 
   Disassemble a little-endian or32 instruction
 
 
 
   Print one instruction from MEMADDR on INFO->STREAM.
 
 
 
   @param[in] memaddr   Address of the instruction to print
 
   @param[in] info      Info about the disassembly, in particular with the
 
                        stream to write to.
 
 
 
   @return   The size of the instruction (always 4 on or32).
 
   --------------------------------------------------------------------------*/
 
 
 
int
int
print_insn_little_or32 (bfd_vma                  memaddr,
print_insn_little_or32 (bfd_vma memaddr, struct disassemble_info *info)
                        struct disassemble_info *info)
 
{
{
  info->private_data = find_bytes_little;
  info->private_data = find_bytes_little;
 
 
  return print_insn (memaddr, info);
  return print_insn (memaddr, info);
 
}
}       /* print_insn_little_or32() */
 
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

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