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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [gdb/] [or32-tdep.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
/* Target-dependent code for the 32-bit OpenRISC 1000, for the GNU Debugger.
/* Target-dependent code for the 32-bit OpenRISC 1000, for the GNU Debugger.
 
 
   Copyright 1988-2008, Free Software Foundation, Inc.
   Copyright 1988-2008, Free Software Foundation, Inc.
   Copyright (C) 2008, 2010 Embecosm Limited
   Copyright (C) 2008, 2010 Embecosm Limited
 
 
   Contributed by Alessandro Forin(af@cs.cmu.edu at CMU
   Contributed by Alessandro Forin(af@cs.cmu.edu at CMU
   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin.
   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin.
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
 
   This file is part of GDB.
   This file is part of GDB.
 
 
   This program is free software; you can redistribute it and/or modify it
   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
   under the terms of the GNU General Public License as published by the Free
   Software Foundation; either version 3 of the License, or (at your option)
   Software Foundation; either version 3 of the License, or (at your option)
   any later version.
   any later version.
 
 
   This program is distributed in the hope that it will be useful, but WITHOUT
   This program 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 or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   more details.
   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 along
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
/*-----------------------------------------------------------------------------
/*-----------------------------------------------------------------------------
   This version for the OpenRISC 1000 architecture is a rewrite by Jeremy
   This version for the OpenRISC 1000 architecture is a rewrite by Jeremy
   Bennett of the old GDB 5.3 interface to make use of gdbarch for GDB 6.8.
   Bennett of the old GDB 5.3 interface to make use of gdbarch for GDB 6.8.
 
 
   The code tries to follow the GDB coding style.
   The code tries to follow the GDB coding style.
 
 
   Commenting is Doxygen compatible.
   Commenting is Doxygen compatible.
 
 
   Much has been stripped out in the interests of getting a basic working
   Much has been stripped out in the interests of getting a basic working
   system. This is described as the OpenRISC 1000 target architecture, so
   system. This is described as the OpenRISC 1000 target architecture, so
   should work with 16, 32 and 64 bit versions of that architecture and should
   should work with 16, 32 and 64 bit versions of that architecture and should
   work whether or not they have floating point and/or vector registers.
   work whether or not they have floating point and/or vector registers.
 
 
   There was never a capability to run simulator commands (no remote target
   There was never a capability to run simulator commands (no remote target
   implemented the required function), so that has been removed.
   implemented the required function), so that has been removed.
 
 
   The info trace command has been removed. The meaning of this is not clear -
   The info trace command has been removed. The meaning of this is not clear -
   it relies on a value in register 255 of the debug group, which is
   it relies on a value in register 255 of the debug group, which is
   undocumented.
   undocumented.
 
 
   All the hardware trace has been removed for the time being. The new debug
   All the hardware trace has been removed for the time being. The new debug
   interface does not support hardware trace, so there is no plan to reinstate
   interface does not support hardware trace, so there is no plan to reinstate
   this functionality.
   this functionality.
 
 
   Support for multiple contexts (which was rudimentary, and not working) has
   Support for multiple contexts (which was rudimentary, and not working) has
   been removed. */
   been removed. */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
#include "demangle.h"
#include "demangle.h"
#include "defs.h"
#include "defs.h"
#include "gdb_string.h"
#include "gdb_string.h"
#include "frame.h"
#include "frame.h"
#include "inferior.h"
#include "inferior.h"
#include "symtab.h"
#include "symtab.h"
#include "value.h"
#include "value.h"
#include "gdbcmd.h"
#include "gdbcmd.h"
#include "language.h"
#include "language.h"
#include "gdbcore.h"
#include "gdbcore.h"
#include "symfile.h"
#include "symfile.h"
#include "objfiles.h"
#include "objfiles.h"
#include "gdbtypes.h"
#include "gdbtypes.h"
#include "target.h"
#include "target.h"
#include "regcache.h"
#include "regcache.h"
 
 
#include "opcode/or32.h"
#include "opcode/or32.h"
#include "or32-tdep.h"
#include "or32-tdep.h"
 
 
#include "safe-ctype.h"
#include "safe-ctype.h"
#include "block.h"
#include "block.h"
#include "reggroups.h"
#include "reggroups.h"
#include "arch-utils.h"
#include "arch-utils.h"
#include "frame.h"
#include "frame.h"
#include "frame-unwind.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "frame-base.h"
#include "dwarf2-frame.h"
#include "dwarf2-frame.h"
#include "trad-frame.h"
#include "trad-frame.h"
 
 
#include <inttypes.h>
#include <inttypes.h>
 
 
 
 


 
 
/* Support functions for the architecture definition */
/* Support functions for the architecture definition */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Get an instruction
/*!Get an instruction
 
 
   This reads from memory. The old version relied on the frame, this relies
   This reads from memory. The old version relied on the frame, this relies
   just on the architecture. The old version also guaranteed not to get a
   just on the architecture. The old version also guaranteed not to get a
   software breakpoint if one had been set. However that seems to happen just
   software breakpoint if one had been set. However that seems to happen just
   before execution and is removed immediately after, so we believe should not
   before execution and is removed immediately after, so we believe should not
   happen. The old function from GDB 6.8 to do this has been deleted.
   happen. The old function from GDB 6.8 to do this has been deleted.
 
 
   @param[in] gdbarch  Architecture for which we are getting the instruction.
   @param[in] gdbarch  Architecture for which we are getting the instruction.
   @param[in] addr     Address from which to get the instruction
   @param[in] addr     Address from which to get the instruction
 
 
   @return  The instruction */
   @return  The instruction */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static ULONGEST
static ULONGEST
or32_fetch_instruction (struct gdbarch *gdbarch,
or32_fetch_instruction (struct gdbarch *gdbarch,
                        CORE_ADDR       addr)
                        CORE_ADDR       addr)
{
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  char            buf[OR32_INSTLEN];
  char            buf[OR32_INSTLEN];
  int             status;
  int             status;
 
 
  status = target_read_memory (addr, buf, OR32_INSTLEN);
  status = target_read_memory (addr, buf, OR32_INSTLEN);
 
 
  if (status)
  if (status)
    {
    {
      memory_error (status, addr);
      memory_error (status, addr);
    }
    }
 
 
  return  extract_unsigned_integer (buf, OR32_INSTLEN, byte_order);
  return  extract_unsigned_integer (buf, OR32_INSTLEN, byte_order);
 
 
}       /* or32_fetch_instruction() */
}       /* or32_fetch_instruction() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Generic function to read bits from an instruction
/*!Generic function to read bits from an instruction
 
 
   printf style. Basic syntax
   printf style. Basic syntax
 
 
      or32_analyse_inst (inst, format, &arg1, &arg2 ...)
      or32_analyse_inst (inst, format, &arg1, &arg2 ...)
 
 
   Format string can contain the following characters:
   Format string can contain the following characters:
 
 
   - SPACE:  Ignored, just for layout
   - SPACE:  Ignored, just for layout
   - 0:      Match with a zero bit
   - 0:      Match with a zero bit
   - 1:      Match with a one bit
   - 1:      Match with a one bit
   - %<n>b:  Match <n> bits to the next argument (n decimal)
   - %<n>b:  Match <n> bits to the next argument (n decimal)
 
 
   If the arg corresponding to a bit field is non-null, the value will be
   If the arg corresponding to a bit field is non-null, the value will be
   assigned to that argument (using NULL allows fields to be skipped).
   assigned to that argument (using NULL allows fields to be skipped).
 
 
   Any bad string will cause a fatal error. These are constant strings, so
   Any bad string will cause a fatal error. These are constant strings, so
   should be correct.
   should be correct.
 
 
   The bit field must be 32 bits long. A failure here will cause a fatal error
   The bit field must be 32 bits long. A failure here will cause a fatal error
   for the same reason.
   for the same reason.
 
 
   @note The format string is presented MS field to LS field, left to
   @note The format string is presented MS field to LS field, left to
         right. This means that it is read lowest numbered char first.
         right. This means that it is read lowest numbered char first.
 
 
   @note Some of the arg fields may be populated, even if recognition
   @note Some of the arg fields may be populated, even if recognition
         ultimately fails.
         ultimately fails.
 
 
   @param[in]  inst    The instruction to analyse
   @param[in]  inst    The instruction to analyse
   @param[in]  format  The format string
   @param[in]  format  The format string
   @param[out] ...     Argument fields
   @param[out] ...     Argument fields
 
 
   @return  1 (TRUE) if the instruction matches, 0 (FALSE) otherwise.        */
   @return  1 (TRUE) if the instruction matches, 0 (FALSE) otherwise.        */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static int
static int
or32_analyse_inst (uint32_t    inst,
or32_analyse_inst (uint32_t    inst,
                   const char *format,
                   const char *format,
                   ...)
                   ...)
{
{
  /* Break out each field in turn, validating as we go. */
  /* Break out each field in turn, validating as we go. */
  va_list     ap;
  va_list     ap;
 
 
  int         i;
  int         i;
  int         iptr = 0;                  /* Instruction pointer */
  int         iptr = 0;                  /* Instruction pointer */
 
 
  va_start (ap, format);
  va_start (ap, format);
 
 
  for (i = 0; 0 != format[i];)
  for (i = 0; 0 != format[i];)
    {
    {
      const char *start_ptr;
      const char *start_ptr;
      char       *end_ptr;
      char       *end_ptr;
 
 
      uint32_t    bits;                 /* Bit substring of interest */
      uint32_t    bits;                 /* Bit substring of interest */
      uint32_t    width;                /* Substring width */
      uint32_t    width;                /* Substring width */
      uint32_t   *arg_ptr;
      uint32_t   *arg_ptr;
 
 
      switch (format[i])
      switch (format[i])
        {
        {
        case ' ': i++; break;   /* Formatting: ignored */
        case ' ': i++; break;   /* Formatting: ignored */
 
 
        case '0': case '1':     /* Constant bit field */
        case '0': case '1':     /* Constant bit field */
          bits = (inst >> (OR32_INSTBITLEN - iptr - 1)) & 0x1;
          bits = (inst >> (OR32_INSTBITLEN - iptr - 1)) & 0x1;
 
 
          if ((format[i] - '0') != bits)
          if ((format[i] - '0') != bits)
            {
            {
              return  0;
              return  0;
            }
            }
 
 
          iptr++;
          iptr++;
          i++;
          i++;
          break;
          break;
 
 
        case '%':               /* Bit field */
        case '%':               /* Bit field */
          i++;
          i++;
          start_ptr = &(format[i]);
          start_ptr = &(format[i]);
          width     = strtoul (start_ptr, &end_ptr, 10);
          width     = strtoul (start_ptr, &end_ptr, 10);
 
 
          /* Check we got something, and if so skip on */
          /* Check we got something, and if so skip on */
          if (start_ptr == end_ptr)
          if (start_ptr == end_ptr)
            {
            {
              fatal ("bitstring \"%s\" at offset %d has no length field.\n",
              fatal ("bitstring \"%s\" at offset %d has no length field.\n",
                     format, i);
                     format, i);
            }
            }
 
 
          i += end_ptr - start_ptr;
          i += end_ptr - start_ptr;
 
 
          /* Look for and skip the terminating 'b'. If it's not there, we
          /* Look for and skip the terminating 'b'. If it's not there, we
             still give a fatal error, because these are fixed strings that
             still give a fatal error, because these are fixed strings that
             just should not be wrong. */
             just should not be wrong. */
          if ('b' != format[i++])
          if ('b' != format[i++])
            {
            {
              fatal ("bitstring \"%s\" at offset %d has no terminating 'b'.\n",
              fatal ("bitstring \"%s\" at offset %d has no terminating 'b'.\n",
                     format, i);
                     format, i);
            }
            }
 
 
          /* Break out the field. There is a special case with a bit width of
          /* Break out the field. There is a special case with a bit width of
             32. */
             32. */
          if (32 == width)
          if (32 == width)
            {
            {
              bits = inst;
              bits = inst;
            }
            }
          else
          else
            {
            {
              bits = (inst >> (OR32_INSTBITLEN - iptr - width)) & ((1 << width) - 1);
              bits = (inst >> (OR32_INSTBITLEN - iptr - width)) & ((1 << width) - 1);
            }
            }
 
 
          arg_ptr   = va_arg (ap, uint32_t *);
          arg_ptr   = va_arg (ap, uint32_t *);
          *arg_ptr  = bits;
          *arg_ptr  = bits;
          iptr     += width;
          iptr     += width;
          break;
          break;
 
 
        default:
        default:
          fatal ("invalid character in bitstring \"%s\" at offset %d.\n",
          fatal ("invalid character in bitstring \"%s\" at offset %d.\n",
                 format, i);
                 format, i);
          break;
          break;
        }
        }
    }
    }
 
 
  /* Is the length OK? */
  /* Is the length OK? */
  gdb_assert (OR32_INSTBITLEN == iptr);
  gdb_assert (OR32_INSTBITLEN == iptr);
 
 
  return  1;                            /* We succeeded */
  return  1;                            /* We succeeded */
 
 
}       /* or32_analyse_inst () */
}       /* or32_analyse_inst () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Analyse a l.addi instruction
/*!Analyse a l.addi instruction
 
 
   General form is:
   General form is:
 
 
     l.addi  rD,rA,I
     l.addi  rD,rA,I
 
 
   Makes use of the generic analysis function (@see or32_analyse_inst ()).
   Makes use of the generic analysis function (@see or32_analyse_inst ()).
 
 
   @param[in]  inst      The instruction to analyse.
   @param[in]  inst      The instruction to analyse.
   @param[out] rd_ptr    Pointer to the rD value.
   @param[out] rd_ptr    Pointer to the rD value.
   @param[out] ra_ptr    Pointer to the rA value.
   @param[out] ra_ptr    Pointer to the rA value.
   @param[out] simm_ptr  Pointer to the signed immediate value.
   @param[out] simm_ptr  Pointer to the signed immediate value.
 
 
   @return  1 (TRUE) if the instruction matches, 0 (FALSE) otherwise.        */
   @return  1 (TRUE) if the instruction matches, 0 (FALSE) otherwise.        */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static int
static int
or32_analyse_l_addi (uint32_t      inst,
or32_analyse_l_addi (uint32_t      inst,
                     unsigned int *rd_ptr,
                     unsigned int *rd_ptr,
                     unsigned int *ra_ptr,
                     unsigned int *ra_ptr,
                     int          *simm_ptr)
                     int          *simm_ptr)
{
{
  /* Instruction fields */
  /* Instruction fields */
  uint32_t  rd, ra, i;
  uint32_t  rd, ra, i;
 
 
  if (or32_analyse_inst (inst, "10 0111 %5b %5b %16b", &rd, &ra, &i))
  if (or32_analyse_inst (inst, "10 0111 %5b %5b %16b", &rd, &ra, &i))
    {
    {
      /* Found it. Construct the result fields */
      /* Found it. Construct the result fields */
      *rd_ptr   = (unsigned int) rd;
      *rd_ptr   = (unsigned int) rd;
      *ra_ptr   = (unsigned int) ra;
      *ra_ptr   = (unsigned int) ra;
      *simm_ptr = (int) (((i & 0x8000) == 0x8000) ? 0xffff0000 | i : i);
      *simm_ptr = (int) (((i & 0x8000) == 0x8000) ? 0xffff0000 | i : i);
 
 
      return  1;                /* Success */
      return  1;                /* Success */
    }
    }
  else
  else
    {
    {
      return  0;         /* Failure */
      return  0;         /* Failure */
    }
    }
}       /* or32_analyse_l_addi () */
}       /* or32_analyse_l_addi () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Analyse a l.sw instruction
/*!Analyse a l.sw instruction
 
 
   General form is:
   General form is:
 
 
     l.sw  I(rA),rB
     l.sw  I(rA),rB
 
 
   Makes use of the generic analysis function (@see or32_analyse_inst ()).
   Makes use of the generic analysis function (@see or32_analyse_inst ()).
 
 
   @param[in]  inst      The instruction to analyse.
   @param[in]  inst      The instruction to analyse.
   @param[out] simm_ptr  Pointer to the signed immediate value.
   @param[out] simm_ptr  Pointer to the signed immediate value.
   @param[out] ra_ptr    Pointer to the rA value.
   @param[out] ra_ptr    Pointer to the rA value.
   @param[out] rb_ptr    Pointer to the rB value.
   @param[out] rb_ptr    Pointer to the rB value.
 
 
   @return  1 (TRUE) if the instruction matches, 0 (FALSE) otherwise.        */
   @return  1 (TRUE) if the instruction matches, 0 (FALSE) otherwise.        */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static int
static int
or32_analyse_l_sw (uint32_t      inst,
or32_analyse_l_sw (uint32_t      inst,
                   int          *simm_ptr,
                   int          *simm_ptr,
                   unsigned int *ra_ptr,
                   unsigned int *ra_ptr,
                   unsigned int *rb_ptr)
                   unsigned int *rb_ptr)
{
{
  /* Instruction fields */
  /* Instruction fields */
  uint32_t  ihi, ilo, ra, rb;
  uint32_t  ihi, ilo, ra, rb;
 
 
  if (or32_analyse_inst (inst, "11 0101 %5b %5b %5b %11b", &ihi, &ra, &rb,
  if (or32_analyse_inst (inst, "11 0101 %5b %5b %5b %11b", &ihi, &ra, &rb,
                         &ilo))
                         &ilo))
 
 
    {
    {
      /* Found it. Construct the result fields */
      /* Found it. Construct the result fields */
      *simm_ptr  = (int) ((ihi << 11) | ilo);
      *simm_ptr  = (int) ((ihi << 11) | ilo);
      *simm_ptr |= ((ihi & 0x10) == 0x10) ? 0xffff0000 : 0;
      *simm_ptr |= ((ihi & 0x10) == 0x10) ? 0xffff0000 : 0;
 
 
      *ra_ptr    = (unsigned int) ra;
      *ra_ptr    = (unsigned int) ra;
      *rb_ptr    = (unsigned int) rb;
      *rb_ptr    = (unsigned int) rb;
 
 
      return  1;                /* Success */
      return  1;                /* Success */
    }
    }
  else
  else
    {
    {
      return  0;         /* Failure */
      return  0;         /* Failure */
    }
    }
}       /* or32_analyse_l_sw () */
}       /* or32_analyse_l_sw () */
 
 
 
 


 
 
/* Functions defining the architecture */
/* Functions defining the architecture */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Determine the return convention used for a given type
/*!Determine the return convention used for a given type
 
 
   Optionally, fetch or set the return value via "readbuf" or "writebuf"
   Optionally, fetch or set the return value via "readbuf" or "writebuf"
   respectively using "regcache" for the register values.
   respectively using "regcache" for the register values.
 
 
   The OpenRISC 1000 returns scalar values via R11 and (for 64 bit values on
   The OpenRISC 1000 returns scalar values via R11 and (for 64 bit values on
   32 bit architectures) R12. Structs and unions are returned by reference,
   32 bit architectures) R12. Structs and unions are returned by reference,
   with the address in R11
   with the address in R11
 
 
   The result returned is independent of the function type, so we ignore that.
   The result returned is independent of the function type, so we ignore that.
 
 
   Throughout use read_memory(), not target_read_memory(), since the address
   Throughout use read_memory(), not target_read_memory(), since the address
   may be invalid and we want an error reported (read_memory() is
   may be invalid and we want an error reported (read_memory() is
   target_read_memory() with error reporting).
   target_read_memory() with error reporting).
 
 
   @todo This implementation is labelled OR32, but in fact is just for the 32
   @todo This implementation is labelled OR32, but in fact is just for the 32
         bit version, OR32. This should be made explicit
         bit version, OR32. This should be made explicit
 
 
   @param[in]  gdbarch   The GDB architecture being used
   @param[in]  gdbarch   The GDB architecture being used
   @param[in]  functype  The type of the function to be called (may be NULL)
   @param[in]  functype  The type of the function to be called (may be NULL)
   @param[in]  valtype   The type of the entity to be returned
   @param[in]  valtype   The type of the entity to be returned
   @param[in]  regcache  The register cache
   @param[in]  regcache  The register cache
   @param[in]  readbuf   Buffer into which the return value should be written
   @param[in]  readbuf   Buffer into which the return value should be written
   @param[out] writebuf  Buffer from which the return value should be written
   @param[out] writebuf  Buffer from which the return value should be written
 
 
   @return  The type of return value */
   @return  The type of return value */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static enum return_value_convention
static enum return_value_convention
or32_return_value (struct gdbarch  *gdbarch,
or32_return_value (struct gdbarch  *gdbarch,
                   struct type     *functype,
                   struct type     *functype,
                   struct type     *valtype,
                   struct type     *valtype,
                   struct regcache *regcache,
                   struct regcache *regcache,
                   gdb_byte        *readbuf,
                   gdb_byte        *readbuf,
                   const gdb_byte  *writebuf)
                   const gdb_byte  *writebuf)
{
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  enum type_code  rv_type    = TYPE_CODE (valtype);
  enum type_code  rv_type    = TYPE_CODE (valtype);
  unsigned int    rv_size    = TYPE_LENGTH (valtype);
  unsigned int    rv_size    = TYPE_LENGTH (valtype);
  ULONGEST        tmp;
  ULONGEST        tmp;
 
 
  /* Deal with struct/union and large scalars first. Large (> 4 byte) scalars
  /* Deal with struct/union and large scalars first. Large (> 4 byte) scalars
     are returned via a pointer (despite what is says in the architecture
     are returned via a pointer (despite what is says in the architecture
     document). Result pointed to by R11 */
     document). Result pointed to by R11 */
 
 
  if((TYPE_CODE_STRUCT == rv_type) ||
  if((TYPE_CODE_STRUCT == rv_type) ||
     (TYPE_CODE_UNION  == rv_type) ||
     (TYPE_CODE_UNION  == rv_type) ||
     (rv_size          >  4))
     (rv_size          >  4))
    {
    {
      if (readbuf)
      if (readbuf)
        {
        {
          regcache_cooked_read_unsigned (regcache, OR32_RV_REGNUM, &tmp);
          regcache_cooked_read_unsigned (regcache, OR32_RV_REGNUM, &tmp);
          read_memory (tmp, readbuf, rv_size);
          read_memory (tmp, readbuf, rv_size);
        }
        }
      if (writebuf)
      if (writebuf)
        {
        {
          regcache_cooked_read_unsigned (regcache, OR32_RV_REGNUM, &tmp);
          regcache_cooked_read_unsigned (regcache, OR32_RV_REGNUM, &tmp);
          write_memory (tmp, writebuf, rv_size);
          write_memory (tmp, writebuf, rv_size);
        }
        }
 
 
      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
    }
    }
 
 
  /* 1-4 byte scalars are returned in R11 */
  /* 1-4 byte scalars are returned in R11 */
 
 
  if (readbuf)
  if (readbuf)
    {
    {
      regcache_cooked_read_unsigned (regcache, OR32_RV_REGNUM, &tmp);
      regcache_cooked_read_unsigned (regcache, OR32_RV_REGNUM, &tmp);
      store_unsigned_integer (readbuf, rv_size, byte_order, tmp);
      store_unsigned_integer (readbuf, rv_size, byte_order, tmp);
    }
    }
  if (writebuf)
  if (writebuf)
    {
    {
      gdb_byte buf[4];
      gdb_byte buf[4];
      memset (buf, 0, sizeof (buf));     /* Pad with zeros if < 4 bytes */
      memset (buf, 0, sizeof (buf));     /* Pad with zeros if < 4 bytes */
 
 
      if (BFD_ENDIAN_BIG == byte_order)
      if (BFD_ENDIAN_BIG == byte_order)
        {
        {
          memcpy (buf + sizeof (buf) - rv_size, writebuf, rv_size);
          memcpy (buf + sizeof (buf) - rv_size, writebuf, rv_size);
        }
        }
      else
      else
        {
        {
          memcpy (buf,                          writebuf, rv_size);
          memcpy (buf,                          writebuf, rv_size);
        }
        }
 
 
      regcache_cooked_write (regcache, OR32_RV_REGNUM, buf);
      regcache_cooked_write (regcache, OR32_RV_REGNUM, buf);
    }
    }
 
 
  return RETURN_VALUE_REGISTER_CONVENTION;
  return RETURN_VALUE_REGISTER_CONVENTION;
 
 
}       /* or32_return_value() */
}       /* or32_return_value() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Determine the instruction to use for a breakpoint.
/*!Determine the instruction to use for a breakpoint.
 
 
   Given the address at which to insert a breakpoint (bp_addr), what will
   Given the address at which to insert a breakpoint (bp_addr), what will
   that breakpoint be?
   that breakpoint be?
 
 
   For or32, we have a breakpoint instruction. Since all or32 instructions
   For or32, we have a breakpoint instruction. Since all or32 instructions
   are 32 bits, this is all we need, regardless of address.
   are 32 bits, this is all we need, regardless of address.
 
 
   @param[in]  gdbarch  The GDB architecture being used
   @param[in]  gdbarch  The GDB architecture being used
   @param[in]  bp_addr  The breakpoint address in question
   @param[in]  bp_addr  The breakpoint address in question
   @param[out] bp_size  The size of instruction selected
   @param[out] bp_size  The size of instruction selected
 
 
   @return  The chosen breakpoint instruction */
   @return  The chosen breakpoint instruction */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static const gdb_byte *
static const gdb_byte *
or32_breakpoint_from_pc (struct gdbarch *gdbarch,
or32_breakpoint_from_pc (struct gdbarch *gdbarch,
                         CORE_ADDR      *bp_addr,
                         CORE_ADDR      *bp_addr,
                         int            *bp_size)
                         int            *bp_size)
{
{
  static const gdb_byte breakpoint[] = OR32_BRK_INSTR_STRUCT;
  static const gdb_byte breakpoint[] = OR32_BRK_INSTR_STRUCT;
 
 
  *bp_size = OR32_INSTLEN;
  *bp_size = OR32_INSTLEN;
  return breakpoint;
  return breakpoint;
 
 
}       /* or32_breakpoint_from_pc() */
}       /* or32_breakpoint_from_pc() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Determine if we are executing a delay slot
/*!Determine if we are executing a delay slot
 
 
   Looks at the instruction at the previous instruction to see if it was one
   Looks at the instruction at the previous instruction to see if it was one
   with a delay slot. But it also has to be the address prior to NPC, because
   with a delay slot. But it also has to be the address prior to NPC, because
   we may have just taken an exception.
   we may have just taken an exception.
 
 
   @param[in] gdbarch     The GDB architecture being used
   @param[in] gdbarch     The GDB architecture being used
   @param[in] this_frame  Information about THIS frame
   @param[in] this_frame  Information about THIS frame
 
 
   @return  1 (true) if this instruction is executing a delay slot, 0 (false)
   @return  1 (true) if this instruction is executing a delay slot, 0 (false)
   otherwise. */
   otherwise. */
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
 
 
static int
static int
or32_single_step_through_delay( struct gdbarch    *gdbarch,
or32_single_step_through_delay( struct gdbarch    *gdbarch,
                                struct frame_info *this_frame )
                                struct frame_info *this_frame )
{
{
  struct regcache   *regcache = get_current_regcache ();
  struct regcache   *regcache = get_current_regcache ();
  ULONGEST           val;
  ULONGEST           val;
  CORE_ADDR          ppc;
  CORE_ADDR          ppc;
  CORE_ADDR          npc;
  CORE_ADDR          npc;
  int                index;
  int                index;
 
 
  /* Get and the previous and current instruction addresses. If they are not
  /* Get and the previous and current instruction addresses. If they are not
     adjacent, we cannot be in a delay slot. */
     adjacent, we cannot be in a delay slot. */
  regcache_cooked_read_unsigned (regcache, OR32_PPC_REGNUM, &val);
  regcache_cooked_read_unsigned (regcache, OR32_PPC_REGNUM, &val);
  ppc        = (CORE_ADDR) val;
  ppc        = (CORE_ADDR) val;
  regcache_cooked_read_unsigned (regcache, OR32_NPC_REGNUM, &val);
  regcache_cooked_read_unsigned (regcache, OR32_NPC_REGNUM, &val);
  npc        = (CORE_ADDR) val;
  npc        = (CORE_ADDR) val;
 
 
  if (0x4 != (npc - ppc))
  if (0x4 != (npc - ppc))
    {
    {
      return  0;
      return  0;
    }
    }
 
 
  /* Decode the previous instruction to see if it was a branch or a jump, and
  /* Decode the previous instruction to see if it was a branch or a jump, and
     hence we are in a delay slot. */
     hence we are in a delay slot. */
  index = insn_decode (or32_fetch_instruction (gdbarch, ppc));
  index = insn_decode (or32_fetch_instruction (gdbarch, ppc));
  return  or32_opcodes[index].flags & OR32_IF_DELAY;
  return  or32_opcodes[index].flags & OR32_IF_DELAY;
 
 
}       /* or32_single_step_through_delay() */
}       /* or32_single_step_through_delay() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Read a pseudo register
/*!Read a pseudo register
 
 
   Since we have no pseudo registers this is a null function for now.
   Since we have no pseudo registers this is a null function for now.
 
 
   @todo The floating point and vector registers ought to be done as
   @todo The floating point and vector registers ought to be done as
         pseudo-registers.
         pseudo-registers.
 
 
   @param[in]  gdbarch   The GDB architecture to consider
   @param[in]  gdbarch   The GDB architecture to consider
   @param[in]  regcache  The cached register values as an array
   @param[in]  regcache  The cached register values as an array
   @param[in]  regnum    The register to read
   @param[in]  regnum    The register to read
   @param[out] buf       A buffer to put the result in */
   @param[out] buf       A buffer to put the result in */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or32_pseudo_register_read (struct gdbarch  *gdbarch,
or32_pseudo_register_read (struct gdbarch  *gdbarch,
                           struct regcache *regcache,
                           struct regcache *regcache,
                           int              regnum,
                           int              regnum,
                           gdb_byte        *buf)
                           gdb_byte        *buf)
{
{
  return;
  return;
 
 
}       /* or32_pseudo_register_read() */
}       /* or32_pseudo_register_read() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Write a pseudo register
/*!Write a pseudo register
 
 
   Since we have no pseudo registers this is a null function for now.
   Since we have no pseudo registers this is a null function for now.
 
 
   @todo The floating point and vector registers ought to be done as
   @todo The floating point and vector registers ought to be done as
         pseudo-registers.
         pseudo-registers.
 
 
   @param[in] gdbarch   The GDB architecture to consider
   @param[in] gdbarch   The GDB architecture to consider
   @param[in] regcache  The cached register values as an array
   @param[in] regcache  The cached register values as an array
   @param[in] regnum    The register to read
   @param[in] regnum    The register to read
   @param[in] buf       A buffer with the value to write */
   @param[in] buf       A buffer with the value to write */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or32_pseudo_register_write (struct gdbarch  *gdbarch,
or32_pseudo_register_write (struct gdbarch  *gdbarch,
                            struct regcache *regcache,
                            struct regcache *regcache,
                            int              regnum,
                            int              regnum,
                            const gdb_byte  *buf)
                            const gdb_byte  *buf)
{
{
  return;
  return;
 
 
}       /* or32_pseudo_register_write() */
}       /* or32_pseudo_register_write() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Return the register name for the OpenRISC 1000 architecture
/*!Return the register name for the OpenRISC 1000 architecture
 
 
   This version converted to ANSI C, made static and incorporates the static
   This version converted to ANSI C, made static and incorporates the static
   table of register names (this is the only place it is referenced).
   table of register names (this is the only place it is referenced).
 
 
   @todo The floating point and vector registers ought to be done as
   @todo The floating point and vector registers ought to be done as
         pseudo-registers.
         pseudo-registers.
 
 
   @param[in] gdbarch  The GDB architecture being used
   @param[in] gdbarch  The GDB architecture being used
   @param[in] regnum    The register number
   @param[in] regnum    The register number
 
 
   @return  The textual name of the register */
   @return  The textual name of the register */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static const char *
static const char *
or32_register_name (struct gdbarch *gdbarch,
or32_register_name (struct gdbarch *gdbarch,
                    int             regnum)
                    int             regnum)
{
{
  static char *or32_gdb_reg_names[OR32_TOTAL_NUM_REGS] =
  static char *or32_gdb_reg_names[OR32_TOTAL_NUM_REGS] =
    {
    {
      /* general purpose registers */
      /* general purpose registers */
      "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
      "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
      "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
      "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
      "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
      "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
      "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
      "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
 
 
      /* previous program counter, next program counter and status register */
      /* previous program counter, next program counter and status register */
      "ppc",   "npc",   "sr"
      "ppc",   "npc",   "sr"
 
 
      /* Floating point and vector registers may appear as pseudo registers in
      /* Floating point and vector registers may appear as pseudo registers in
         the future. */
         the future. */
    };
    };
 
 
  return or32_gdb_reg_names[regnum];
  return or32_gdb_reg_names[regnum];
 
 
}       /* or32_register_name() */
}       /* or32_register_name() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Identify the type of a register
/*!Identify the type of a register
 
 
   @todo I don't fully understand exactly what this does, but I think this
   @todo I don't fully understand exactly what this does, but I think this
         makes sense!
         makes sense!
 
 
   @param[in] arch     The GDB architecture to consider
   @param[in] arch     The GDB architecture to consider
   @param[in] regnum   The register to identify
   @param[in] regnum   The register to identify
 
 
   @return  The type of the register */
   @return  The type of the register */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static struct type *
static struct type *
or32_register_type (struct gdbarch *arch,
or32_register_type (struct gdbarch *arch,
                    int             regnum)
                    int             regnum)
{
{
  static struct type *void_func_ptr = NULL;
  static struct type *void_func_ptr = NULL;
  static struct type *void_ptr      = NULL;
  static struct type *void_ptr      = NULL;
 
 
  /* Set up the static pointers once, the first time*/
  /* Set up the static pointers once, the first time*/
  if (NULL == void_func_ptr)
  if (NULL == void_func_ptr)
    {
    {
      struct type *void_type = builtin_type (arch)->builtin_void;
      struct type *void_type = builtin_type (arch)->builtin_void;
 
 
      void_ptr      = lookup_pointer_type (void_type);
      void_ptr      = lookup_pointer_type (void_type);
      void_func_ptr = lookup_pointer_type (lookup_function_type (void_type));
      void_func_ptr = lookup_pointer_type (lookup_function_type (void_type));
    }
    }
 
 
  if((regnum >= 0) && (regnum < OR32_TOTAL_NUM_REGS))
  if((regnum >= 0) && (regnum < OR32_TOTAL_NUM_REGS))
    {
    {
      switch (regnum)
      switch (regnum)
        {
        {
        case OR32_PPC_REGNUM:
        case OR32_PPC_REGNUM:
        case OR32_NPC_REGNUM:
        case OR32_NPC_REGNUM:
          return void_func_ptr;                 /* Pointer to code */
          return void_func_ptr;                 /* Pointer to code */
 
 
        case OR32_SP_REGNUM:
        case OR32_SP_REGNUM:
        case OR32_FP_REGNUM:
        case OR32_FP_REGNUM:
          return void_ptr;                              /* Pointer to data */
          return void_ptr;                              /* Pointer to data */
 
 
        default:
        default:
          return builtin_type (arch)->builtin_uint32;   /* Data */
          return builtin_type (arch)->builtin_uint32;   /* Data */
        }
        }
    }
    }
 
 
  internal_error (__FILE__, __LINE__,
  internal_error (__FILE__, __LINE__,
                  _("or32_register_type: illegal register number %d"), regnum);
                  _("or32_register_type: illegal register number %d"), regnum);
 
 
}       /* or32_register_type() */
}       /* or32_register_type() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Handle the "info register" command
/*!Handle the "info register" command
 
 
   Print the identified register, unless it is -1, in which case print all
   Print the identified register, unless it is -1, in which case print all
   the registers. If all is 1 means all registers, otherwise only the core
   the registers. If all is 1 means all registers, otherwise only the core
   GPRs.
   GPRs.
 
 
   @todo At present all registers are printed with the default method. Should
   @todo At present all registers are printed with the default method. Should
         there be something special for FP registers?
         there be something special for FP registers?
 
 
   @param[in] gdbarch  The GDB architecture being used
   @param[in] gdbarch  The GDB architecture being used
   @param[in] file     File handle for use with any custom I/O
   @param[in] file     File handle for use with any custom I/O
   @param[in] frame    Frame info for use with custom output
   @param[in] frame    Frame info for use with custom output
   @param[in] regnum   Register of interest, or -1 if all registers
   @param[in] regnum   Register of interest, or -1 if all registers
   @param[in] all      1 if all means all, 0 if all means just GPRs
   @param[in] all      1 if all means all, 0 if all means just GPRs
 
 
   @return  The aligned stack frame address */
   @return  The aligned stack frame address */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or32_registers_info (struct gdbarch    *gdbarch,
or32_registers_info (struct gdbarch    *gdbarch,
                     struct ui_file    *file,
                     struct ui_file    *file,
                     struct frame_info *frame,
                     struct frame_info *frame,
                     int                regnum,
                     int                regnum,
                     int                all)
                     int                all)
{
{
  if (-1 == regnum)
  if (-1 == regnum)
    {
    {
      /* Do all (valid) registers */
      /* Do all (valid) registers */
      unsigned int  lim = all ? OR32_NUM_REGS : OR32_MAX_GPR_REGS;
      unsigned int  lim = all ? OR32_NUM_REGS : OR32_MAX_GPR_REGS;
 
 
      for (regnum = 0; regnum < lim; regnum++) {
      for (regnum = 0; regnum < lim; regnum++) {
        if ('\0' != *(or32_register_name (gdbarch, regnum)))
        if ('\0' != *(or32_register_name (gdbarch, regnum)))
          {
          {
            or32_registers_info (gdbarch, file, frame, regnum, all);
            or32_registers_info (gdbarch, file, frame, regnum, all);
          }
          }
      }
      }
    }
    }
  else
  else
    {
    {
      /* Do one specified register - if it is part of this architecture */
      /* Do one specified register - if it is part of this architecture */
      if ('\0' == *(or32_register_name (gdbarch, regnum)))
      if ('\0' == *(or32_register_name (gdbarch, regnum)))
        {
        {
          error ("Not a valid register for the current processor type");
          error ("Not a valid register for the current processor type");
        }
        }
      else
      else
        {
        {
          default_print_registers_info (gdbarch, file, frame, regnum, all);
          default_print_registers_info (gdbarch, file, frame, regnum, all);
        }
        }
    }
    }
}       /* or32_registers_info() */
}       /* or32_registers_info() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Identify if a register belongs to a specified group
/*!Identify if a register belongs to a specified group
 
 
   Return true if the specified register is a member of the specified
   Return true if the specified register is a member of the specified
   register group.
   register group.
 
 
   These are the groups of registers that can be displayed via "info reg".
   These are the groups of registers that can be displayed via "info reg".
 
 
   @todo The Vector and Floating Point registers ought to be displayed as
   @todo The Vector and Floating Point registers ought to be displayed as
         pseudo-registers.
         pseudo-registers.
 
 
   @param[in] gdbarch  The GDB architecture to consider
   @param[in] gdbarch  The GDB architecture to consider
   @param[in] regnum   The register to consider
   @param[in] regnum   The register to consider
   @param[in] group    The group to consider
   @param[in] group    The group to consider
 
 
   @return  True (1) if regnum is a member of group */
   @return  True (1) if regnum is a member of group */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or32_register_reggroup_p (struct gdbarch  *gdbarch,
or32_register_reggroup_p (struct gdbarch  *gdbarch,
                          int              regnum,
                          int              regnum,
                          struct reggroup *group)
                          struct reggroup *group)
{
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
 
  /* All register group */
  /* All register group */
  if (group == all_reggroup)
  if (group == all_reggroup)
    {
    {
      return ((regnum >= 0) &&
      return ((regnum >= 0) &&
              (regnum < OR32_TOTAL_NUM_REGS) &&
              (regnum < OR32_TOTAL_NUM_REGS) &&
              (or32_register_name (gdbarch, regnum)[0] != '\0'));
              (or32_register_name (gdbarch, regnum)[0] != '\0'));
    }
    }
 
 
  /* For now everything except the PC */
  /* For now everything except the PC */
  if (group == general_reggroup)
  if (group == general_reggroup)
    {
    {
      return ((regnum >= OR32_ZERO_REGNUM) &&
      return ((regnum >= OR32_ZERO_REGNUM) &&
              (regnum <  tdep->num_gpr_regs) &&
              (regnum <  tdep->num_gpr_regs) &&
              (regnum != OR32_PPC_REGNUM) &&
              (regnum != OR32_PPC_REGNUM) &&
              (regnum != OR32_NPC_REGNUM));
              (regnum != OR32_NPC_REGNUM));
    }
    }
 
 
  if (group == float_reggroup)
  if (group == float_reggroup)
    {
    {
      return 0;                  /* No float regs.  */
      return 0;                  /* No float regs.  */
    }
    }
 
 
  if (group == vector_reggroup)
  if (group == vector_reggroup)
    {
    {
      return 0;                  /* No vector regs.  */
      return 0;                  /* No vector regs.  */
    }
    }
 
 
  /* For any that are not handled above.  */
  /* For any that are not handled above.  */
  return default_register_reggroup_p (gdbarch, regnum, group);
  return default_register_reggroup_p (gdbarch, regnum, group);
 
 
}       /* or32_register_reggroup_p() */
}       /* or32_register_reggroup_p() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Is this one of the registers used for passing arguments?
/*!Is this one of the registers used for passing arguments?
 
 
   These are r3-r8 in the API.
   These are r3-r8 in the API.
 
 
   @param[in] regnum  The register to consider
   @param[in] regnum  The register to consider
 
 
   @return  Non-zero (TRUE) if it is an argument register, zero (FALSE)
   @return  Non-zero (TRUE) if it is an argument register, zero (FALSE)
            otherwise.                                                        */
            otherwise.                                                        */
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
static int
static int
or32_is_arg_reg (unsigned int  regnum)
or32_is_arg_reg (unsigned int  regnum)
{
{
  return (OR32_FIRST_ARG_REGNUM <= regnum) && (regnum <= OR32_LAST_ARG_REGNUM);
  return (OR32_FIRST_ARG_REGNUM <= regnum) && (regnum <= OR32_LAST_ARG_REGNUM);
 
 
}       /* or32_is_arg_reg () */
}       /* or32_is_arg_reg () */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Is this a callee saved register?
/*!Is this a callee saved register?
 
 
   These are r10, r12, r14, r16, r18, r20, r22, r24, r26, r28 and r30 in the
   These are r10, r12, r14, r16, r18, r20, r22, r24, r26, r28 and r30 in the
   API.
   API.
 
 
   @param[in] regnum  The register to consider
   @param[in] regnum  The register to consider
 
 
   @return  Non-zero (TRUE) if it is a callee saved register, zero (FALSE)
   @return  Non-zero (TRUE) if it is a callee saved register, zero (FALSE)
            otherwise.                                                        */
            otherwise.                                                        */
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
static int
static int
or32_is_callee_saved_reg (unsigned int  regnum)
or32_is_callee_saved_reg (unsigned int  regnum)
{
{
  return (OR32_FIRST_SAVED_REGNUM <= regnum) && (0 == regnum % 2);
  return (OR32_FIRST_SAVED_REGNUM <= regnum) && (0 == regnum % 2);
 
 
}       /* or32_is_callee_saved_reg () */
}       /* or32_is_callee_saved_reg () */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Skip a function prolog
/*!Skip a function prolog
 
 
   If the input address, PC, is in a function prologue, return the address of
   If the input address, PC, is in a function prologue, return the address of
   the end of the prologue, otherwise return the input  address.
   the end of the prologue, otherwise return the input  address.
 
 
   @see For details of the stack frame, see the function
   @see For details of the stack frame, see the function
        or32_frame_cache().
        or32_frame_cache().
 
 
   @note The old version of this function used to use skip_prologue_using_sal
   @note The old version of this function used to use skip_prologue_using_sal
         to skip the prologue without checking if it had actually worked. It
         to skip the prologue without checking if it had actually worked. It
         doesn't for STABS, so we had better check for a valid result.
         doesn't for STABS, so we had better check for a valid result.
 
 
   This function reuses the helper functions from or32_frame_cache() to
   This function reuses the helper functions from or32_frame_cache() to
   locate the various parts of the prolog, any or all of which may be missing.
   locate the various parts of the prolog, any or all of which may be missing.
 
 
   @param[in] gdbarch  The GDB architecture being used
   @param[in] gdbarch  The GDB architecture being used
   @param[in] pc       Current program counter
   @param[in] pc       Current program counter
 
 
   @return  The address of the end of the prolog if the PC is in a function
   @return  The address of the end of the prolog if the PC is in a function
            prologue, otherwise the input  address.                           */
            prologue, otherwise the input  address.                           */
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
static CORE_ADDR
static CORE_ADDR
or32_skip_prologue (struct gdbarch *gdbarch,
or32_skip_prologue (struct gdbarch *gdbarch,
                    CORE_ADDR       pc)
                    CORE_ADDR       pc)
{
{
  CORE_ADDR     start_pc;
  CORE_ADDR     start_pc;
  CORE_ADDR     addr;
  CORE_ADDR     addr;
  uint32_t      inst;
  uint32_t      inst;
 
 
  unsigned int  ra, rb, rd;             /* For instruction analysis */
  unsigned int  ra, rb, rd;             /* For instruction analysis */
  int           simm;
  int           simm;
 
 
  int           frame_size = 0;
  int           frame_size = 0;
 
 
  /* Try using SAL first if we have symbolic information available. This only
  /* Try using SAL first if we have symbolic information available. This only
     works for DWARF 2, not STABS. */
     works for DWARF 2, not STABS. */
  if (find_pc_partial_function (pc, NULL, &start_pc, NULL))
  if (find_pc_partial_function (pc, NULL, &start_pc, NULL))
    {
    {
      CORE_ADDR  prologue_end = skip_prologue_using_sal( gdbarch, pc );
      CORE_ADDR  prologue_end = skip_prologue_using_sal( gdbarch, pc );
 
 
      if (0 != prologue_end)
      if (0 != prologue_end)
        {
        {
          struct symtab_and_line  prologue_sal = find_pc_line (start_pc, 0);
          struct symtab_and_line  prologue_sal = find_pc_line (start_pc, 0);
          char *debug_format = prologue_sal.symtab->debugformat;
          char *debug_format = prologue_sal.symtab->debugformat;
 
 
          if ((strlen ("dwarf") <= strlen (debug_format))
          if ((strlen ("dwarf") <= strlen (debug_format))
              && (0 == strncasecmp ("dwarf", debug_format, strlen ("dwarf"))))
              && (0 == strncasecmp ("dwarf", debug_format, strlen ("dwarf"))))
            {
            {
              return  (prologue_end > pc) ? prologue_end : pc;
              return  (prologue_end > pc) ? prologue_end : pc;
            }
            }
        }
        }
    }
    }
 
 
  /* Look to see if we can find any of the standard prologue sequence. All
  /* Look to see if we can find any of the standard prologue sequence. All
     quite difficult, since any or all of it may be missing. So this is just a
     quite difficult, since any or all of it may be missing. So this is just a
     best guess! */
     best guess! */
  addr = pc;                            /* Where we have got to */
  addr = pc;                            /* Where we have got to */
  inst = or32_fetch_instruction (gdbarch, addr);
  inst = or32_fetch_instruction (gdbarch, addr);
 
 
  /* Look for the new stack pointer being set up. */
  /* Look for the new stack pointer being set up. */
  if (or32_analyse_l_addi (inst, &rd, &ra, &simm) &&
  if (or32_analyse_l_addi (inst, &rd, &ra, &simm) &&
      (OR32_SP_REGNUM == rd) && (OR32_SP_REGNUM == ra) &&
      (OR32_SP_REGNUM == rd) && (OR32_SP_REGNUM == ra) &&
      (simm < 0) && (0 == (simm % 4)))
      (simm < 0) && (0 == (simm % 4)))
    {
    {
      frame_size  = -simm;
      frame_size  = -simm;
      addr       += OR32_INSTLEN;
      addr       += OR32_INSTLEN;
      inst        = or32_fetch_instruction (gdbarch, addr);
      inst        = or32_fetch_instruction (gdbarch, addr);
    }
    }
 
 
  /* Look for the frame pointer being manipulated. */
  /* Look for the frame pointer being manipulated. */
  if (or32_analyse_l_sw (inst, &simm, &ra, &rb) &&
  if (or32_analyse_l_sw (inst, &simm, &ra, &rb) &&
      (OR32_SP_REGNUM == ra) && (OR32_FP_REGNUM == rb) &&
      (OR32_SP_REGNUM == ra) && (OR32_FP_REGNUM == rb) &&
      (simm >= 0) && (0 == (simm % 4)))
      (simm >= 0) && (0 == (simm % 4)))
    {
    {
      addr += OR32_INSTLEN;
      addr += OR32_INSTLEN;
      inst  = or32_fetch_instruction (gdbarch, addr);
      inst  = or32_fetch_instruction (gdbarch, addr);
 
 
      gdb_assert (or32_analyse_l_addi (inst, &rd, &ra, &simm) &&
      gdb_assert (or32_analyse_l_addi (inst, &rd, &ra, &simm) &&
                  (OR32_FP_REGNUM == rd) && (OR32_SP_REGNUM == ra) &&
                  (OR32_FP_REGNUM == rd) && (OR32_SP_REGNUM == ra) &&
                  (simm == frame_size));
                  (simm == frame_size));
 
 
      addr += OR32_INSTLEN;
      addr += OR32_INSTLEN;
      inst  = or32_fetch_instruction (gdbarch, addr);
      inst  = or32_fetch_instruction (gdbarch, addr);
    }
    }
 
 
  /* Look for the link register being saved */
  /* Look for the link register being saved */
  if (or32_analyse_l_sw (inst, &simm, &ra, &rb) &&
  if (or32_analyse_l_sw (inst, &simm, &ra, &rb) &&
      (OR32_SP_REGNUM == ra) && (OR32_LR_REGNUM == rb) &&
      (OR32_SP_REGNUM == ra) && (OR32_LR_REGNUM == rb) &&
      (simm >= 0) && (0 == (simm % 4)))
      (simm >= 0) && (0 == (simm % 4)))
    {
    {
      addr += OR32_INSTLEN;
      addr += OR32_INSTLEN;
      inst  = or32_fetch_instruction (gdbarch, addr);
      inst  = or32_fetch_instruction (gdbarch, addr);
    }
    }
 
 
  /* Look for arguments or callee-saved register being saved. The register
  /* Look for arguments or callee-saved register being saved. The register
     must be one of the arguments (r3-r8) or the 10 callee saved registers
     must be one of the arguments (r3-r8) or the 10 callee saved registers
     (r10, r12, r14, r16, r18, r20, r22, r24, r26, r28, r30). The base
     (r10, r12, r14, r16, r18, r20, r22, r24, r26, r28, r30). The base
     register must be the FP (for the args) or the SP (for the callee_saved
     register must be the FP (for the args) or the SP (for the callee_saved
     registers). */
     registers). */
  while (1)
  while (1)
    {
    {
      if (or32_analyse_l_sw (inst, &simm, &ra, &rb) &&
      if (or32_analyse_l_sw (inst, &simm, &ra, &rb) &&
          (((OR32_FP_REGNUM == ra) && or32_is_arg_reg (rb)) ||
          (((OR32_FP_REGNUM == ra) && or32_is_arg_reg (rb)) ||
           ((OR32_SP_REGNUM == ra) && or32_is_callee_saved_reg (rb))) &&
           ((OR32_SP_REGNUM == ra) && or32_is_callee_saved_reg (rb))) &&
          (0 == (simm % 4)))
          (0 == (simm % 4)))
        {
        {
          addr += OR32_INSTLEN;
          addr += OR32_INSTLEN;
          inst  = or32_fetch_instruction (gdbarch, addr);
          inst  = or32_fetch_instruction (gdbarch, addr);
        }
        }
      else
      else
        {
        {
          /* Nothing else to look for. We have found the end of the prologue. */
          /* Nothing else to look for. We have found the end of the prologue. */
          return  addr;
          return  addr;
        }
        }
    }
    }
}       /* or32_skip_prologue() */
}       /* or32_skip_prologue() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Align the stack frame
/*!Align the stack frame
 
 
   OpenRISC 1000 uses a falling stack frame, so this aligns down to the
   OpenRISC 1000 uses a falling stack frame, so this aligns down to the
   nearest 8 bytes. Useful when we'be building a dummy frame.
   nearest 8 bytes. Useful when we'be building a dummy frame.
 
 
   @param[in] gdbarch  The GDB architecture being used
   @param[in] gdbarch  The GDB architecture being used
   @param[in] sp       Current stack pointer
   @param[in] sp       Current stack pointer
 
 
   @return  The aligned stack frame address */
   @return  The aligned stack frame address */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static CORE_ADDR
static CORE_ADDR
or32_frame_align (struct gdbarch *gdbarch,
or32_frame_align (struct gdbarch *gdbarch,
                  CORE_ADDR       sp)
                  CORE_ADDR       sp)
{
{
  return align_down (sp, OR32_STACK_ALIGN);
  return align_down (sp, OR32_STACK_ALIGN);
 
 
}       /* or32_frame_align() */
}       /* or32_frame_align() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Unwind the program counter from a stack frame
/*!Unwind the program counter from a stack frame
 
 
   This just uses the built in frame unwinder
   This just uses the built in frame unwinder
 
 
   @param[in] gdbarch     The GDB architecture being used
   @param[in] gdbarch     The GDB architecture being used
   @param[in] next_frame  Frame info for the NEXT frame
   @param[in] next_frame  Frame info for the NEXT frame
 
 
   @return  The program counter for THIS frame */
   @return  The program counter for THIS frame */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static CORE_ADDR
static CORE_ADDR
or32_unwind_pc (struct gdbarch    *gdbarch,
or32_unwind_pc (struct gdbarch    *gdbarch,
                struct frame_info *next_frame)
                struct frame_info *next_frame)
{
{
  CORE_ADDR pc = frame_unwind_register_unsigned (next_frame, OR32_NPC_REGNUM);
  CORE_ADDR pc = frame_unwind_register_unsigned (next_frame, OR32_NPC_REGNUM);
 
 
  return pc;
  return pc;
 
 
}       /* or32_unwind_pc() */
}       /* or32_unwind_pc() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Unwind the stack pointer from a stack frame
/*!Unwind the stack pointer from a stack frame
 
 
   This just uses the built in frame unwinder
   This just uses the built in frame unwinder
 
 
   @param[in] gdbarch     The GDB architecture being used
   @param[in] gdbarch     The GDB architecture being used
   @param[in] next_frame  Frame info for the NEXT frame
   @param[in] next_frame  Frame info for the NEXT frame
 
 
   @return  The stack pointer for THIS frame */
   @return  The stack pointer for THIS frame */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static CORE_ADDR
static CORE_ADDR
or32_unwind_sp (struct gdbarch    *gdbarch,
or32_unwind_sp (struct gdbarch    *gdbarch,
                struct frame_info *next_frame)
                struct frame_info *next_frame)
{
{
  CORE_ADDR sp = frame_unwind_register_unsigned (next_frame, OR32_SP_REGNUM);
  CORE_ADDR sp = frame_unwind_register_unsigned (next_frame, OR32_SP_REGNUM);
 
 
  return sp;
  return sp;
 
 
}       /* or32_unwind_sp() */
}       /* or32_unwind_sp() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Create a dummy stack frame
/*!Create a dummy stack frame
 
 
   The arguments are placed in registers and/or pushed on the stack as per the
   The arguments are placed in registers and/or pushed on the stack as per the
   OR32 ABI.
   OR32 ABI.
 
 
   @param[in] gdbarch        The architecture to use
   @param[in] gdbarch        The architecture to use
   @param[in] function       Pointer to the function that will be called
   @param[in] function       Pointer to the function that will be called
   @param[in] regcache       The register cache to use
   @param[in] regcache       The register cache to use
   @param[in] bp_addr        Breakpoint address
   @param[in] bp_addr        Breakpoint address
   @param[in] nargs          Number of ags to push
   @param[in] nargs          Number of ags to push
   @param[in] args           The arguments
   @param[in] args           The arguments
   @param[in] sp             The stack pointer
   @param[in] sp             The stack pointer
   @param[in] struct_return  True (1) if this returns a structure
   @param[in] struct_return  True (1) if this returns a structure
   @param[in] struct_addr    Address for returning structures
   @param[in] struct_addr    Address for returning structures
 
 
   @return  The updated stack pointer */
   @return  The updated stack pointer */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static CORE_ADDR
static CORE_ADDR
or32_push_dummy_call (struct gdbarch  *gdbarch,
or32_push_dummy_call (struct gdbarch  *gdbarch,
                      struct value    *function,
                      struct value    *function,
                      struct regcache *regcache,
                      struct regcache *regcache,
                      CORE_ADDR        bp_addr,
                      CORE_ADDR        bp_addr,
                      int              nargs,
                      int              nargs,
                      struct value   **args,
                      struct value   **args,
                      CORE_ADDR        sp,
                      CORE_ADDR        sp,
                      int              struct_return,
                      int              struct_return,
                      CORE_ADDR        struct_addr)
                      CORE_ADDR        struct_addr)
{
{
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
 
 
  int             argreg;
  int             argreg;
  int             argnum;
  int             argnum;
  int             first_stack_arg;
  int             first_stack_arg;
  int             stack_offset = 0;
  int             stack_offset = 0;
 
 
  unsigned int    bpa = (gdbarch_tdep (gdbarch))->bytes_per_address;
  unsigned int    bpa = (gdbarch_tdep (gdbarch))->bytes_per_address;
  unsigned int    bpw = (gdbarch_tdep (gdbarch))->bytes_per_word;
  unsigned int    bpw = (gdbarch_tdep (gdbarch))->bytes_per_word;
 
 
  /* Return address */
  /* Return address */
  regcache_cooked_write_unsigned (regcache, OR32_LR_REGNUM, bp_addr);
  regcache_cooked_write_unsigned (regcache, OR32_LR_REGNUM, bp_addr);
 
 
  /* Register for the next argument */
  /* Register for the next argument */
  argreg = OR32_FIRST_ARG_REGNUM;
  argreg = OR32_FIRST_ARG_REGNUM;
 
 
  /* Location for a returned structure. This is passed as a silent first
  /* Location for a returned structure. This is passed as a silent first
     argument. */
     argument. */
 
 
  if (struct_return)
  if (struct_return)
    {
    {
      regcache_cooked_write_unsigned (regcache, OR32_FIRST_ARG_REGNUM,
      regcache_cooked_write_unsigned (regcache, OR32_FIRST_ARG_REGNUM,
                                      struct_addr);
                                      struct_addr);
      argreg++;
      argreg++;
    }
    }
 
 
  /* Put as many args as possible in registers */
  /* Put as many args as possible in registers */
  for (argnum = 0; argnum < nargs; argnum++)
  for (argnum = 0; argnum < nargs; argnum++)
    {
    {
      char           *val;
      char           *val;
      char            valbuf[sizeof (ULONGEST) ];
      char            valbuf[sizeof (ULONGEST) ];
 
 
      struct value   *arg      = args[argnum];
      struct value   *arg      = args[argnum];
      struct type    *arg_type = check_typedef (value_type (arg));
      struct type    *arg_type = check_typedef (value_type (arg));
      int             len      = arg_type->length;
      int             len      = arg_type->length;
      enum type_code  typecode = arg_type->main_type->code;
      enum type_code  typecode = arg_type->main_type->code;
 
 
      /* The EABI passes structures that do not fit in a register by
      /* The EABI passes structures that do not fit in a register by
         reference. In all other cases, pass the structure by value.  */
         reference. In all other cases, pass the structure by value.  */
      if((len > bpw) &&
      if((len > bpw) &&
         ((TYPE_CODE_STRUCT == typecode) || (TYPE_CODE_UNION == typecode)))
         ((TYPE_CODE_STRUCT == typecode) || (TYPE_CODE_UNION == typecode)))
        {
        {
 
 
          store_unsigned_integer (valbuf, bpa, byte_order, value_offset (arg));
          store_unsigned_integer (valbuf, bpa, byte_order, value_offset (arg));
          len      = bpa;
          len      = bpa;
          val      = valbuf;
          val      = valbuf;
        }
        }
      else
      else
        {
        {
          val = (char *)value_contents (arg);
          val = (char *)value_contents (arg);
        }
        }
 
 
      if((len > bpw) && (argreg <= (OR32_LAST_ARG_REGNUM - 1)))
      if((len > bpw) && (argreg <= (OR32_LAST_ARG_REGNUM - 1)))
        {
        {
 
 
          /* Big scalars use two registers, but need NOT be pair aligned. This
          /* Big scalars use two registers, but need NOT be pair aligned. This
             code breaks if we can have quad-word scalars (e.g. long
             code breaks if we can have quad-word scalars (e.g. long
             double). */
             double). */
          ULONGEST regval = extract_unsigned_integer (val, len, byte_order);
          ULONGEST regval = extract_unsigned_integer (val, len, byte_order);
 
 
          unsigned int  bits_per_word = bpw * 8;
          unsigned int  bits_per_word = bpw * 8;
          ULONGEST      mask          = (((ULONGEST) 1) << bits_per_word) - 1;
          ULONGEST      mask          = (((ULONGEST) 1) << bits_per_word) - 1;
          ULONGEST      lo            = regval & mask;
          ULONGEST      lo            = regval & mask;
          ULONGEST      hi            = regval >> bits_per_word;
          ULONGEST      hi            = regval >> bits_per_word;
 
 
          gdb_assert (len <= (bpw * 2));
          gdb_assert (len <= (bpw * 2));
 
 
          regcache_cooked_write_unsigned (regcache, argreg,     hi);
          regcache_cooked_write_unsigned (regcache, argreg,     hi);
          regcache_cooked_write_unsigned (regcache, argreg + 1, lo);
          regcache_cooked_write_unsigned (regcache, argreg + 1, lo);
          argreg += 2;
          argreg += 2;
        }
        }
      else if (argreg <= OR32_LAST_ARG_REGNUM)
      else if (argreg <= OR32_LAST_ARG_REGNUM)
        {
        {
          printf ("Writing 0x%08llx to r%d\n",
          printf ("Writing 0x%08llx to r%d\n",
                  extract_unsigned_integer (val, len, byte_order), argreg);
                  extract_unsigned_integer (val, len, byte_order), argreg);
 
 
          regcache_cooked_write_unsigned (regcache, argreg,
          regcache_cooked_write_unsigned (regcache, argreg,
                                          extract_unsigned_integer (val, len,
                                          extract_unsigned_integer (val, len,
                                                                   byte_order));
                                                                   byte_order));
          argreg++;
          argreg++;
        }
        }
      else
      else
        {
        {
          /* Run out of regs */
          /* Run out of regs */
          break;
          break;
        }
        }
    }
    }
 
 
  first_stack_arg = argnum;
  first_stack_arg = argnum;
 
 
  /* If we get here with argnum < nargs, then arguments remain to be placed on
  /* If we get here with argnum < nargs, then arguments remain to be placed on
     the stack. This is tricky, since they must be pushed in reverse order and
     the stack. This is tricky, since they must be pushed in reverse order and
     the stack in the end must be aligned. The only solution is to do it in
     the stack in the end must be aligned. The only solution is to do it in
     two stages, the first to compute the stack size, the second to save the
     two stages, the first to compute the stack size, the second to save the
     args. */
     args. */
 
 
  for (argnum = first_stack_arg; argnum < nargs; argnum++)
  for (argnum = first_stack_arg; argnum < nargs; argnum++)
    {
    {
      struct value   *arg      = args[argnum];
      struct value   *arg      = args[argnum];
      struct type    *arg_type = check_typedef (value_type (arg));
      struct type    *arg_type = check_typedef (value_type (arg));
      int             len      = arg_type->length;
      int             len      = arg_type->length;
      enum type_code  typecode = arg_type->main_type->code;
      enum type_code  typecode = arg_type->main_type->code;
 
 
      if((len > bpw) &&
      if((len > bpw) &&
         ((TYPE_CODE_STRUCT == typecode) || (TYPE_CODE_UNION == typecode)))
         ((TYPE_CODE_STRUCT == typecode) || (TYPE_CODE_UNION == typecode)))
        {
        {
          /* Large structures are passed as addresses */
          /* Large structures are passed as addresses */
          sp -= bpa;
          sp -= bpa;
        }
        }
      else
      else
        {
        {
        /* Big scalars use more than one word. Code here allows for future
        /* Big scalars use more than one word. Code here allows for future
         quad-word entities (e.g. long double) */
         quad-word entities (e.g. long double) */
          sp -= ((len + bpw - 1) / bpw) * bpw;
          sp -= ((len + bpw - 1) / bpw) * bpw;
        }
        }
    }
    }
 
 
  sp           = gdbarch_frame_align (gdbarch, sp);
  sp           = gdbarch_frame_align (gdbarch, sp);
  stack_offset = 0;
  stack_offset = 0;
 
 
  /* Push the remaining args on the stack */
  /* Push the remaining args on the stack */
  for (argnum = first_stack_arg; argnum < nargs; argnum++)
  for (argnum = first_stack_arg; argnum < nargs; argnum++)
    {
    {
      char           *val;
      char           *val;
      char            valbuf[sizeof (ULONGEST) ];
      char            valbuf[sizeof (ULONGEST) ];
 
 
      struct value   *arg      = args[argnum];
      struct value   *arg      = args[argnum];
      struct type    *arg_type = check_typedef (value_type (arg));
      struct type    *arg_type = check_typedef (value_type (arg));
      int             len      = arg_type->length;
      int             len      = arg_type->length;
      enum type_code  typecode = arg_type->main_type->code;
      enum type_code  typecode = arg_type->main_type->code;
 
 
      /* The EABI passes structures that do not fit in a register by
      /* The EABI passes structures that do not fit in a register by
         reference. In all other cases, pass the structure by value.  */
         reference. In all other cases, pass the structure by value.  */
      if((len > bpw) &&
      if((len > bpw) &&
         ((TYPE_CODE_STRUCT == typecode) || (TYPE_CODE_UNION == typecode)))
         ((TYPE_CODE_STRUCT == typecode) || (TYPE_CODE_UNION == typecode)))
        {
        {
 
 
          store_unsigned_integer (valbuf, bpa, byte_order, value_offset (arg));
          store_unsigned_integer (valbuf, bpa, byte_order, value_offset (arg));
          len      = bpa;
          len      = bpa;
          val      = valbuf;
          val      = valbuf;
        }
        }
      else
      else
        {
        {
          val = (char *)value_contents (arg);
          val = (char *)value_contents (arg);
        }
        }
 
 
      gdb_assert (len <= (bpw * 2));
      gdb_assert (len <= (bpw * 2));
 
 
      write_memory (sp + stack_offset, val, len);
      write_memory (sp + stack_offset, val, len);
      stack_offset += ((len + bpw - 1) / bpw) * bpw;
      stack_offset += ((len + bpw - 1) / bpw) * bpw;
    }
    }
 
 
  /* Save the updated stack pointer */
  /* Save the updated stack pointer */
  regcache_cooked_write_unsigned (regcache, OR32_SP_REGNUM, sp);
  regcache_cooked_write_unsigned (regcache, OR32_SP_REGNUM, sp);
 
 
  return sp;
  return sp;
 
 
}       /* or32_push_dummy_call() */
}       /* or32_push_dummy_call() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Return the frame ID for a dummy stack frame
/*!Return the frame ID for a dummy stack frame
 
 
   Tear down a dummy frame created by or32_push_dummy_call(). This data has to
   Tear down a dummy frame created by or32_push_dummy_call(). This data has to
   be constructed manually from the data in our hand.
   be constructed manually from the data in our hand.
 
 
   The stack pointer and program counter can be obtained from the frame info.
   The stack pointer and program counter can be obtained from the frame info.
 
 
   @param[in] gdbarch     The architecture to use
   @param[in] gdbarch     The architecture to use
   @param[in] this_frame  Information about this frame
   @param[in] this_frame  Information about this frame
 
 
   @return  Frame ID of this frame */
   @return  Frame ID of this frame */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static struct frame_id
static struct frame_id
or32_dummy_id (struct gdbarch    *gdbarch,
or32_dummy_id (struct gdbarch    *gdbarch,
               struct frame_info *this_frame)
               struct frame_info *this_frame)
{
{
  return  frame_id_build (get_frame_sp (this_frame), get_frame_pc (this_frame));
  return  frame_id_build (get_frame_sp (this_frame), get_frame_pc (this_frame));
 
 
}       /* or32_dummy_id() */
}       /* or32_dummy_id() */
 
 
 
 


 
 
/* Support functions for frame handling */
/* Support functions for frame handling */
 
 
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/*!Initialize a prologue cache
/*!Initialize a prologue cache
 
 
   This function is changed from its GDB 6.8 version (named
   This function is changed from its GDB 6.8 version (named
   or32_frame_unwind_cache), in that it is based on THIS frame, not the NEXT
   or32_frame_unwind_cache), in that it is based on THIS frame, not the NEXT
   frame.
   frame.
 
 
   We build a cache, saying where registers of the PREV frame can be found
   We build a cache, saying where registers of the PREV frame can be found
   from the data so far set up in this THIS.
   from the data so far set up in this THIS.
 
 
   We also compute a unique ID for this frame, based on the function start
   We also compute a unique ID for this frame, based on the function start
   address and the stack pointer (as it will be, even if it has yet to be
   address and the stack pointer (as it will be, even if it has yet to be
   computed.
   computed.
 
 
   STACK FORMAT
   STACK FORMAT
   ============
   ============
 
 
   The OR32 has a falling stack frame and a simple prolog. The Stack pointer
   The OR32 has a falling stack frame and a simple prolog. The Stack pointer
   is R1 and the frame pointer R2. The frame base is therefore the address
   is R1 and the frame pointer R2. The frame base is therefore the address
   held in R2 and the stack pointer (R1) is the frame base of the NEXT frame.
   held in R2 and the stack pointer (R1) is the frame base of the NEXT frame.
 
 
   @verbatim
   @verbatim
   l.addi  r1,r1,-frame_size    # SP now points to end of new stack frame
   l.addi  r1,r1,-frame_size    # SP now points to end of new stack frame
   @endverbatim
   @endverbatim
 
 
   The stack pointer may not be set up in a frameless function (e.g. a simple
   The stack pointer may not be set up in a frameless function (e.g. a simple
   leaf function).
   leaf function).
 
 
   @verbatim
   @verbatim
   l.sw    fp_loc(r1),r2        # old FP saved in new stack frame
   l.sw    fp_loc(r1),r2        # old FP saved in new stack frame
   l.addi  r2,r1,frame_size     # FP now points to base of new stack frame
   l.addi  r2,r1,frame_size     # FP now points to base of new stack frame
   @endverbatim
   @endverbatim
 
 
   The frame pointer is not necessarily saved right at the end of the stack
   The frame pointer is not necessarily saved right at the end of the stack
   frame - OR32 saves enough space for any args to called functions right at
   frame - OR32 saves enough space for any args to called functions right at
   the end (this is a difference from the Architecture Manual).
   the end (this is a difference from the Architecture Manual).
 
 
   @verbatim
   @verbatim
   l.sw    lr_loc(r1),r9        # Link (return) address
   l.sw    lr_loc(r1),r9        # Link (return) address
   @endverbatim
   @endverbatim
 
 
   The link register is usally saved at fp_loc - 4. It may not be saved at all
   The link register is usally saved at fp_loc - 4. It may not be saved at all
   in a leaf function.
   in a leaf function.
 
 
   @verbatim
   @verbatim
   l.sw    reg_loc(r1),ry       # Save any callee saved regs
   l.sw    reg_loc(r1),ry       # Save any callee saved regs
   @endverbatim
   @endverbatim
 
 
   The offsets x for the callee saved registers generally (always?) rise in
   The offsets x for the callee saved registers generally (always?) rise in
   increments of 4, starting at fp_loc + 4. If the frame pointer is omitted
   increments of 4, starting at fp_loc + 4. If the frame pointer is omitted
   (an option to GCC), then it may not be saved at all. There may be no callee
   (an option to GCC), then it may not be saved at all. There may be no callee
   saved registers.
   saved registers.
 
 
   So in summary none of this may be present. However what is present seems
   So in summary none of this may be present. However what is present seems
   always to follow this fixed order, and occur before any substantive code
   always to follow this fixed order, and occur before any substantive code
   (it is possible for GCC to have more flexible scheduling of the prologue,
   (it is possible for GCC to have more flexible scheduling of the prologue,
   but this does not seem to occur for OR32).
   but this does not seem to occur for OR32).
 
 
   ANALYSIS
   ANALYSIS
   ========
   ========
 
 
   This prolog is used, even for -O3 with GCC.
   This prolog is used, even for -O3 with GCC.
 
 
   All this analysis must allow for the possibility that the PC is in the
   All this analysis must allow for the possibility that the PC is in the
   middle of the prologue. Data in the cache should only be set up insofar as
   middle of the prologue. Data in the cache should only be set up insofar as
   it has been computed.
   it has been computed.
 
 
   HOWEVER. The frame_id must be created with the SP *as it will be* at the
   HOWEVER. The frame_id must be created with the SP *as it will be* at the
   end of the Prologue. Otherwise a recursive call, checking the frame with
   end of the Prologue. Otherwise a recursive call, checking the frame with
   the PC at the start address will end up with the same frame_id as the
   the PC at the start address will end up with the same frame_id as the
   caller.
   caller.
 
 
   A suite of "helper" routines are used, allowing reuse for
   A suite of "helper" routines are used, allowing reuse for
   or32_skip_prologue().
   or32_skip_prologue().
 
 
   Reportedly, this is only valid for frames less than 0x7fff in size.
   Reportedly, this is only valid for frames less than 0x7fff in size.
 
 
   @param[in]     this_frame      Our stack frame.
   @param[in]     this_frame      Our stack frame.
   @param[in,out] prologue_cache  The prologue cache. If not supplied, we
   @param[in,out] prologue_cache  The prologue cache. If not supplied, we
                                  build it.
                                  build it.
 
 
   @return  The prolog cache (duplicates the return through the argument) */
   @return  The prolog cache (duplicates the return through the argument) */
/* ---------------------------------------------------------------------------*/
/* ---------------------------------------------------------------------------*/
static struct trad_frame_cache *
static struct trad_frame_cache *
or32_frame_cache (struct frame_info  *this_frame,
or32_frame_cache (struct frame_info  *this_frame,
                  void              **prologue_cache)
                  void              **prologue_cache)
{
{
  struct gdbarch          *gdbarch;
  struct gdbarch          *gdbarch;
  struct trad_frame_cache *info;
  struct trad_frame_cache *info;
 
 
  CORE_ADDR                this_pc;
  CORE_ADDR                this_pc;
  CORE_ADDR                this_sp;
  CORE_ADDR                this_sp;
  CORE_ADDR                this_sp_for_id;
  CORE_ADDR                this_sp_for_id;
  int                      frame_size = 0;
  int                      frame_size = 0;
 
 
  CORE_ADDR                start_addr;
  CORE_ADDR                start_addr;
  CORE_ADDR                end_addr;
  CORE_ADDR                end_addr;
 
 
  /* Nothing to do if we already have this info */
  /* Nothing to do if we already have this info */
  if (NULL != *prologue_cache)
  if (NULL != *prologue_cache)
    {
    {
      return *prologue_cache;
      return *prologue_cache;
    }
    }
 
 
  /* Get a new prologue cache and populate it with default values */
  /* Get a new prologue cache and populate it with default values */
  info                 = trad_frame_cache_zalloc (this_frame);
  info                 = trad_frame_cache_zalloc (this_frame);
  *prologue_cache = info;
  *prologue_cache = info;
 
 
  /* Find the start address of THIS function (which is a NORMAL frame, even if
  /* Find the start address of THIS function (which is a NORMAL frame, even if
     the NEXT frame is the sentinel frame) and the end of its prologue.  */
     the NEXT frame is the sentinel frame) and the end of its prologue.  */
  this_pc = get_frame_pc (this_frame);
  this_pc = get_frame_pc (this_frame);
  find_pc_partial_function (this_pc, NULL, &start_addr, NULL);
  find_pc_partial_function (this_pc, NULL, &start_addr, NULL);
 
 
  /* Return early if GDB couldn't find the function.  */
  /* Return early if GDB couldn't find the function.  */
  if (start_addr == 0)
  if (start_addr == 0)
    {
    {
      return  info;
      return  info;
    }
    }
 
 
  /* Get the stack pointer if we have one (if there's no process executing yet
  /* Get the stack pointer if we have one (if there's no process executing yet
     we won't have a frame. */
     we won't have a frame. */
  this_sp = (NULL == this_frame) ? 0 :
  this_sp = (NULL == this_frame) ? 0 :
                                   get_frame_register_unsigned (this_frame,
                                   get_frame_register_unsigned (this_frame,
                                                                OR32_SP_REGNUM);
                                                                OR32_SP_REGNUM);
 
 
  /* The default frame base of THIS frame (for ID purposes only - frame base
  /* The default frame base of THIS frame (for ID purposes only - frame base
     is an overloaded term) is its stack pointer. For now we use the value of
     is an overloaded term) is its stack pointer. For now we use the value of
     the SP register in THIS frame. However if the PC is in the prologue of
     the SP register in THIS frame. However if the PC is in the prologue of
     THIS frame, before the SP has been set up, then the value will actually
     THIS frame, before the SP has been set up, then the value will actually
     be that of the PREV frame, and we'll need to adjust it later. */
     be that of the PREV frame, and we'll need to adjust it later. */
  trad_frame_set_this_base (info, this_sp);
  trad_frame_set_this_base (info, this_sp);
  this_sp_for_id = this_sp;
  this_sp_for_id = this_sp;
 
 
  /* The default is to find the PC of the PREVIOUS frame in the link register
  /* The default is to find the PC of the PREVIOUS frame in the link register
     of this frame. This may be changed if we find the link register was saved
     of this frame. This may be changed if we find the link register was saved
     on the stack. */
     on the stack. */
  trad_frame_set_reg_realreg (info, OR32_NPC_REGNUM, OR32_LR_REGNUM);
  trad_frame_set_reg_realreg (info, OR32_NPC_REGNUM, OR32_LR_REGNUM);
 
 
  /* We should only examine code that is in the prologue. This is all code up
  /* We should only examine code that is in the prologue. This is all code up
     to (but not including) end_addr. We should only populate the cache while
     to (but not including) end_addr. We should only populate the cache while
     the address is up to (but not including) the PC or end_addr, whichever is
     the address is up to (but not including) the PC or end_addr, whichever is
     first. */
     first. */
  gdbarch = get_frame_arch (this_frame);
  gdbarch = get_frame_arch (this_frame);
  end_addr = or32_skip_prologue (gdbarch, start_addr);
  end_addr = or32_skip_prologue (gdbarch, start_addr);
 
 
  /* All the following analysis only occurs if we are in the prologue and have
  /* All the following analysis only occurs if we are in the prologue and have
     executed the code. Check we have a sane prologue size, and if zero we
     executed the code. Check we have a sane prologue size, and if zero we
     are frameless and can give up here. */
     are frameless and can give up here. */
  if (end_addr < start_addr)
  if (end_addr < start_addr)
    {
    {
      fatal ("end addr 0x%08x is less than start addr 0x%08x\n",
      fatal ("end addr 0x%08x is less than start addr 0x%08x\n",
             (unsigned int) end_addr, (unsigned int) start_addr);
             (unsigned int) end_addr, (unsigned int) start_addr);
    }
    }
 
 
  if (end_addr == start_addr)
  if (end_addr == start_addr)
    {
    {
      frame_size = 0;
      frame_size = 0;
    }
    }
  else
  else
    {
    {
      /* have a frame. Look for the various components */
      /* have a frame. Look for the various components */
      CORE_ADDR  addr = start_addr;     /* Where we have got to */
      CORE_ADDR  addr = start_addr;     /* Where we have got to */
      uint32_t   inst = or32_fetch_instruction (gdbarch, addr);
      uint32_t   inst = or32_fetch_instruction (gdbarch, addr);
 
 
      unsigned int  ra, rb, rd;         /* For instruction analysis */
      unsigned int  ra, rb, rd;         /* For instruction analysis */
      int           simm;
      int           simm;
 
 
      /* Look for the new stack pointer being set up. */
      /* Look for the new stack pointer being set up. */
      if (or32_analyse_l_addi (inst, &rd, &ra, &simm) &&
      if (or32_analyse_l_addi (inst, &rd, &ra, &simm) &&
          (OR32_SP_REGNUM == rd) && (OR32_SP_REGNUM == ra) &&
          (OR32_SP_REGNUM == rd) && (OR32_SP_REGNUM == ra) &&
          (simm < 0) && (0 == (simm % 4)))
          (simm < 0) && (0 == (simm % 4)))
        {
        {
          frame_size  = -simm;
          frame_size  = -simm;
          addr       += OR32_INSTLEN;
          addr       += OR32_INSTLEN;
          inst        = or32_fetch_instruction (gdbarch, addr);
          inst        = or32_fetch_instruction (gdbarch, addr);
 
 
          /* If the PC has not actually got to this point, then the frame base
          /* If the PC has not actually got to this point, then the frame base
             will be wrong, and we adjust it.
             will be wrong, and we adjust it.
 
 
             If we are past this point, then we need to populate the stack
             If we are past this point, then we need to populate the stack
             accoringly. */
             accoringly. */
          if (this_pc <= addr)
          if (this_pc <= addr)
            {
            {
              /* Only do if executing */
              /* Only do if executing */
              if (0 != this_sp)
              if (0 != this_sp)
                {
                {
                  this_sp_for_id = this_sp + frame_size;
                  this_sp_for_id = this_sp + frame_size;
                  trad_frame_set_this_base (info, this_sp_for_id);
                  trad_frame_set_this_base (info, this_sp_for_id);
                }
                }
            }
            }
          else
          else
            {
            {
              /* We are past this point, so the stack pointer of the PREV
              /* We are past this point, so the stack pointer of the PREV
                 frame is frame_size greater than the stack pointer of THIS
                 frame is frame_size greater than the stack pointer of THIS
                 frame. */
                 frame. */
              trad_frame_set_reg_value (info, OR32_SP_REGNUM,
              trad_frame_set_reg_value (info, OR32_SP_REGNUM,
                                        this_sp + frame_size);
                                        this_sp + frame_size);
            }
            }
        }
        }
 
 
      /* From now on we are only populating the cache, so we stop once we get
      /* From now on we are only populating the cache, so we stop once we get
         to either the end OR the current PC. */
         to either the end OR the current PC. */
      end_addr = (this_pc < end_addr) ? this_pc : end_addr;
      end_addr = (this_pc < end_addr) ? this_pc : end_addr;
 
 
      /* Look for the frame pointer being manipulated. */
      /* Look for the frame pointer being manipulated. */
      if ((addr < end_addr) &&
      if ((addr < end_addr) &&
          or32_analyse_l_sw (inst, &simm, &ra, &rb) &&
          or32_analyse_l_sw (inst, &simm, &ra, &rb) &&
          (OR32_SP_REGNUM == ra) && (OR32_FP_REGNUM == rb) &&
          (OR32_SP_REGNUM == ra) && (OR32_FP_REGNUM == rb) &&
          (simm >= 0) && (0 == (simm % 4)))
          (simm >= 0) && (0 == (simm % 4)))
        {
        {
          addr += OR32_INSTLEN;
          addr += OR32_INSTLEN;
          inst  = or32_fetch_instruction (gdbarch, addr);
          inst  = or32_fetch_instruction (gdbarch, addr);
 
 
          /* At this stage, we can find the frame pointer of the PREVIOUS
          /* At this stage, we can find the frame pointer of the PREVIOUS
             frame on the stack of the current frame. */
             frame on the stack of the current frame. */
          trad_frame_set_reg_addr (info, OR32_FP_REGNUM, this_sp + simm);
          trad_frame_set_reg_addr (info, OR32_FP_REGNUM, this_sp + simm);
 
 
          /* Look for the new frame pointer being set up */
          /* Look for the new frame pointer being set up */
          if (addr < end_addr)
          if (addr < end_addr)
            {
            {
              gdb_assert (or32_analyse_l_addi (inst, &rd, &ra, &simm) &&
              gdb_assert (or32_analyse_l_addi (inst, &rd, &ra, &simm) &&
                          (OR32_FP_REGNUM == rd) && (OR32_SP_REGNUM == ra) &&
                          (OR32_FP_REGNUM == rd) && (OR32_SP_REGNUM == ra) &&
                          (simm == frame_size));
                          (simm == frame_size));
 
 
              addr += OR32_INSTLEN;
              addr += OR32_INSTLEN;
              inst  = or32_fetch_instruction (gdbarch, addr);
              inst  = or32_fetch_instruction (gdbarch, addr);
 
 
              /* If we have got this far, the stack pointer of the PREVIOUS
              /* If we have got this far, the stack pointer of the PREVIOUS
                 frame is the frame pointer of THIS frame. */
                 frame is the frame pointer of THIS frame. */
              trad_frame_set_reg_realreg (info, OR32_SP_REGNUM, OR32_FP_REGNUM);
              trad_frame_set_reg_realreg (info, OR32_SP_REGNUM, OR32_FP_REGNUM);
            }
            }
        }
        }
 
 
      /* Look for the link register being saved */
      /* Look for the link register being saved */
      if ((addr < end_addr) &&
      if ((addr < end_addr) &&
          or32_analyse_l_sw (inst, &simm, &ra, &rb) &&
          or32_analyse_l_sw (inst, &simm, &ra, &rb) &&
          (OR32_SP_REGNUM == ra) && (OR32_LR_REGNUM == rb) &&
          (OR32_SP_REGNUM == ra) && (OR32_LR_REGNUM == rb) &&
          (simm >= 0) && (0 == (simm % 4)))
          (simm >= 0) && (0 == (simm % 4)))
        {
        {
          addr += OR32_INSTLEN;
          addr += OR32_INSTLEN;
          inst  = or32_fetch_instruction (gdbarch, addr);
          inst  = or32_fetch_instruction (gdbarch, addr);
 
 
          /* If the link register is saved in the THIS frame, it holds the
          /* If the link register is saved in the THIS frame, it holds the
             value of the PC in the PREVIOUS frame. This overwrites the
             value of the PC in the PREVIOUS frame. This overwrites the
             previous information about finding the PC in the link
             previous information about finding the PC in the link
             register. */
             register. */
          trad_frame_set_reg_addr (info, OR32_NPC_REGNUM, this_sp + simm);
          trad_frame_set_reg_addr (info, OR32_NPC_REGNUM, this_sp + simm);
        }
        }
 
 
      /* Look for arguments or callee-saved register being saved. The register
      /* Look for arguments or callee-saved register being saved. The register
         must be one of the arguments (r3-r8) or the 10 callee saved registers
         must be one of the arguments (r3-r8) or the 10 callee saved registers
         (r10, r12, r14, r16, r18, r20, r22, r24, r26, r28, r30). The base
         (r10, r12, r14, r16, r18, r20, r22, r24, r26, r28, r30). The base
         register must be the FP (for the args) or the SP (for the
         register must be the FP (for the args) or the SP (for the
         callee_saved registers). */
         callee_saved registers). */
      while (addr < end_addr)
      while (addr < end_addr)
        {
        {
          if (or32_analyse_l_sw (inst, &simm, &ra, &rb) &&
          if (or32_analyse_l_sw (inst, &simm, &ra, &rb) &&
              (((OR32_FP_REGNUM == ra) && or32_is_arg_reg (rb)) ||
              (((OR32_FP_REGNUM == ra) && or32_is_arg_reg (rb)) ||
               ((OR32_SP_REGNUM == ra) && or32_is_callee_saved_reg (rb))) &&
               ((OR32_SP_REGNUM == ra) && or32_is_callee_saved_reg (rb))) &&
              (0 == (simm % 4)))
              (0 == (simm % 4)))
            {
            {
              addr += OR32_INSTLEN;
              addr += OR32_INSTLEN;
              inst  = or32_fetch_instruction (gdbarch, addr);
              inst  = or32_fetch_instruction (gdbarch, addr);
 
 
              /* The register in the PREVIOUS frame can be found at this
              /* The register in the PREVIOUS frame can be found at this
                 location in THIS frame */
                 location in THIS frame */
              trad_frame_set_reg_addr (info, rb, this_sp + simm);
              trad_frame_set_reg_addr (info, rb, this_sp + simm);
            }
            }
          else
          else
            {
            {
              break;                    /* Not a register save instruction */
              break;                    /* Not a register save instruction */
            }
            }
        }
        }
    }
    }
 
 
  /* Build the frame ID */
  /* Build the frame ID */
  trad_frame_set_id (info, frame_id_build (this_sp_for_id, start_addr));
  trad_frame_set_id (info, frame_id_build (this_sp_for_id, start_addr));
 
 
  return info;
  return info;
 
 
}       /* or32_frame_cache() */
}       /* or32_frame_cache() */
 
 
 
 
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/*!Find the frame ID of this frame
/*!Find the frame ID of this frame
 
 
   This function has changed since GDB 6.8 to use THIS frame, rather than the
   This function has changed since GDB 6.8 to use THIS frame, rather than the
   NEXT frame.
   NEXT frame.
 
 
   Given a GDB frame, return its frame_id.
   Given a GDB frame, return its frame_id.
 
 
   @param[in]  this_frame      Our frame, for which the ID is wanted.
   @param[in]  this_frame      Our frame, for which the ID is wanted.
   @param[in]  prologue_cache  Any cached prologue for THIS function.
   @param[in]  prologue_cache  Any cached prologue for THIS function.
   @param[out] this_id         Frame ID of our own frame.
   @param[out] this_id         Frame ID of our own frame.
 
 
   @return  Frame ID for THIS frame */
   @return  Frame ID for THIS frame */
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
static void
static void
or32_frame_this_id (struct frame_info  *this_frame,
or32_frame_this_id (struct frame_info  *this_frame,
                    void              **prologue_cache,
                    void              **prologue_cache,
                    struct frame_id    *this_id)
                    struct frame_id    *this_id)
{
{
  struct trad_frame_cache *info =
  struct trad_frame_cache *info =
    or32_frame_cache (this_frame, prologue_cache);
    or32_frame_cache (this_frame, prologue_cache);
 
 
  trad_frame_get_id (info, this_id);
  trad_frame_get_id (info, this_id);
 
 
}       /* or32_frame_this_id() */
}       /* or32_frame_this_id() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Get a register from the PREVIOUS frame
/*!Get a register from the PREVIOUS frame
 
 
   This function has changed from GDB 6.8. It now takes a reference to THIS
   This function has changed from GDB 6.8. It now takes a reference to THIS
   frame, not the NEXT frame. It returns it results via a structure, not its
   frame, not the NEXT frame. It returns it results via a structure, not its
   argument list.
   argument list.
 
 
   Given a pointer to the THIS frame, return the details of a register in the
   Given a pointer to the THIS frame, return the details of a register in the
   PREVIOUS frame.
   PREVIOUS frame.
 
 
   @param[in] this_frame      The stack frame under consideration
   @param[in] this_frame      The stack frame under consideration
   @param[in] prologue_cache  Any cached prologue associated with THIS frame,
   @param[in] prologue_cache  Any cached prologue associated with THIS frame,
                              which may therefore tell us about registers in
                              which may therefore tell us about registers in
                              the PREVIOUS frame.
                              the PREVIOUS frame.
   @param[in] regnum          The register of interest in the PREVIOUS frame
   @param[in] regnum          The register of interest in the PREVIOUS frame
 
 
   @return  A value structure representing the register.                      */
   @return  A value structure representing the register.                      */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static struct value *
static struct value *
or32_frame_prev_register (struct frame_info  *this_frame,
or32_frame_prev_register (struct frame_info  *this_frame,
                          void              **prologue_cache,
                          void              **prologue_cache,
                          int                 regnum)
                          int                 regnum)
{
{
  struct trad_frame_cache *info = or32_frame_cache (this_frame,
  struct trad_frame_cache *info = or32_frame_cache (this_frame,
                                                    prologue_cache);
                                                    prologue_cache);
 
 
  return  trad_frame_get_register (info, this_frame, regnum);
  return  trad_frame_get_register (info, this_frame, regnum);
 
 
}       /* or32_frame_prev_register() */
}       /* or32_frame_prev_register() */
 
 
 
 
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/*!Structure defining the OR32 frame unwind functions
/*!Structure defining the OR32 frame unwind functions
 
 
   Must be global (to this file), since referred to by multiple functions.
   Must be global (to this file), since referred to by multiple functions.
 
 
   Since we are the fallback unwinder, we use the default frame sniffer, which
   Since we are the fallback unwinder, we use the default frame sniffer, which
   always accepts the frame
   always accepts the frame
 
 
   This applies to NORMAL frames only. We provide the following functions.
   This applies to NORMAL frames only. We provide the following functions.
   - to give the ID of THIS frame
   - to give the ID of THIS frame
   - to give the details of a register in PREVIOUS frame
   - to give the details of a register in PREVIOUS frame
   - a frame sniffer.                                                         */
   - a frame sniffer.                                                         */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static const struct frame_unwind or32_frame_unwind = {
static const struct frame_unwind or32_frame_unwind = {
  .type          = NORMAL_FRAME,
  .type          = NORMAL_FRAME,
  .this_id       = or32_frame_this_id,
  .this_id       = or32_frame_this_id,
  .prev_register = or32_frame_prev_register,
  .prev_register = or32_frame_prev_register,
  .unwind_data   = NULL,
  .unwind_data   = NULL,
  .sniffer       = default_frame_sniffer,
  .sniffer       = default_frame_sniffer,
  .dealloc_cache = NULL,
  .dealloc_cache = NULL,
  .prev_arch     = NULL
  .prev_arch     = NULL
};
};
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Return the base address of the frame
/*!Return the base address of the frame
 
 
   The implementations has changed since GDB 6.8, since we are now provided
   The implementations has changed since GDB 6.8, since we are now provided
   with the address of THIS frame, rather than the NEXT frame.
   with the address of THIS frame, rather than the NEXT frame.
 
 
   For the OR32, the base address is the frame pointer
   For the OR32, the base address is the frame pointer
 
 
   @param[in] this_frame      The current stack frame.
   @param[in] this_frame      The current stack frame.
   @param[in] prologue_cache  Any cached prologue for THIS function.
   @param[in] prologue_cache  Any cached prologue for THIS function.
 
 
   @return  The frame base address */
   @return  The frame base address */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static CORE_ADDR
static CORE_ADDR
or32_frame_base_address (struct frame_info  *this_frame,
or32_frame_base_address (struct frame_info  *this_frame,
                         void              **prologue_cache)
                         void              **prologue_cache)
{
{
  return  (CORE_ADDR) get_frame_register_unsigned (this_frame, OR32_FP_REGNUM);
  return  (CORE_ADDR) get_frame_register_unsigned (this_frame, OR32_FP_REGNUM);
 
 
}       /* or32_frame_base_address() */
}       /* or32_frame_base_address() */
 
 
 
 
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/*!Identify our frame base sniffer functions
/*!Identify our frame base sniffer functions
 
 
   This function just identifies our family of frame sniffing functions.
   This function just identifies our family of frame sniffing functions.
 
 
   @param[in] this_frame  The frame of THIS function. Not used here.
   @param[in] this_frame  The frame of THIS function. Not used here.
 
 
   @return  A pointer to a struct identifying the frame base sniffing
   @return  A pointer to a struct identifying the frame base sniffing
            functions.                                                        */
            functions.                                                        */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static const struct frame_base *
static const struct frame_base *
or32_frame_base_sniffer (struct frame_info *this_frame)
or32_frame_base_sniffer (struct frame_info *this_frame)
{
{
  /* Structure defining how the frame base is to be identified. */
  /* Structure defining how the frame base is to be identified. */
  static const struct frame_base  or32_frame_base =
  static const struct frame_base  or32_frame_base =
    {
    {
      .unwind      = &or32_frame_unwind,
      .unwind      = &or32_frame_unwind,
      .this_base   = or32_frame_base_address,
      .this_base   = or32_frame_base_address,
      .this_locals = or32_frame_base_address,
      .this_locals = or32_frame_base_address,
      .this_args   = or32_frame_base_address
      .this_args   = or32_frame_base_address
    };
    };
 
 
  return &or32_frame_base;
  return &or32_frame_base;
 
 
}       /* or32_frame_base_sniffer () */
}       /* or32_frame_base_sniffer () */
 
 
 
 
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/*!Architecture initialization for OpenRISC 1000
/*!Architecture initialization for OpenRISC 1000
 
 
   Looks for a candidate architecture in the list of architectures supplied
   Looks for a candidate architecture in the list of architectures supplied
   using the info supplied. If none match, create a new architecture.
   using the info supplied. If none match, create a new architecture.
 
 
   @param[in] info    Information about the target architecture
   @param[in] info    Information about the target architecture
   @param[in] arches  The list of currently know architectures
   @param[in] arches  The list of currently know architectures
 
 
   @return  A structure describing the target architecture                    */
   @return  A structure describing the target architecture                    */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static struct gdbarch *
static struct gdbarch *
or32_gdbarch_init (struct gdbarch_info  info,
or32_gdbarch_init (struct gdbarch_info  info,
                   struct gdbarch_list *arches)
                   struct gdbarch_list *arches)
{
{
  static struct frame_base     or32_frame_base;
  static struct frame_base     or32_frame_base;
  struct        gdbarch       *gdbarch;
  struct        gdbarch       *gdbarch;
  struct        gdbarch_tdep  *tdep;
  struct        gdbarch_tdep  *tdep;
  const struct  bfd_arch_info *binfo;
  const struct  bfd_arch_info *binfo;
 
 
  /* Find a candidate among the list of pre-declared architectures.  */
  /* Find a candidate among the list of pre-declared architectures.  */
  arches = gdbarch_list_lookup_by_info (arches, &info);
  arches = gdbarch_list_lookup_by_info (arches, &info);
  if (NULL != arches)
  if (NULL != arches)
    {
    {
      return arches->gdbarch;
      return arches->gdbarch;
    }
    }
 
 
  /* None found, create a new architecture from the information
  /* None found, create a new architecture from the information
     provided. Can't initialize all the target dependencies until we actually
     provided. Can't initialize all the target dependencies until we actually
     know which target we are talking to, but put in some defaults for now. */
     know which target we are talking to, but put in some defaults for now. */
 
 
  binfo                   = info.bfd_arch_info;
  binfo                   = info.bfd_arch_info;
  tdep                    = xmalloc (sizeof *tdep);
  tdep                    = xmalloc (sizeof *tdep);
  tdep->num_matchpoints   = OR32_MAX_MATCHPOINTS;
  tdep->num_matchpoints   = OR32_MAX_MATCHPOINTS;
  tdep->num_gpr_regs      = OR32_MAX_GPR_REGS;
  tdep->num_gpr_regs      = OR32_MAX_GPR_REGS;
  tdep->bytes_per_word    = binfo->bits_per_word    / binfo->bits_per_byte;
  tdep->bytes_per_word    = binfo->bits_per_word    / binfo->bits_per_byte;
  tdep->bytes_per_address = binfo->bits_per_address / binfo->bits_per_byte;
  tdep->bytes_per_address = binfo->bits_per_address / binfo->bits_per_byte;
  gdbarch                 = gdbarch_alloc (&info, tdep);
  gdbarch                 = gdbarch_alloc (&info, tdep);
 
 
  /* Target data types.  */
  /* Target data types.  */
  set_gdbarch_short_bit             (gdbarch, 16);
  set_gdbarch_short_bit             (gdbarch, 16);
  set_gdbarch_int_bit               (gdbarch, 32);
  set_gdbarch_int_bit               (gdbarch, 32);
  set_gdbarch_long_bit              (gdbarch, 32);
  set_gdbarch_long_bit              (gdbarch, 32);
  set_gdbarch_long_long_bit         (gdbarch, 64);
  set_gdbarch_long_long_bit         (gdbarch, 64);
  set_gdbarch_float_bit             (gdbarch, 32);
  set_gdbarch_float_bit             (gdbarch, 32);
  set_gdbarch_float_format          (gdbarch, floatformats_ieee_single);
  set_gdbarch_float_format          (gdbarch, floatformats_ieee_single);
  set_gdbarch_double_bit            (gdbarch, 64);
  set_gdbarch_double_bit            (gdbarch, 64);
  set_gdbarch_double_format         (gdbarch, floatformats_ieee_double);
  set_gdbarch_double_format         (gdbarch, floatformats_ieee_double);
  set_gdbarch_long_double_bit       (gdbarch, 64);
  set_gdbarch_long_double_bit       (gdbarch, 64);
  set_gdbarch_long_double_format    (gdbarch, floatformats_ieee_double);
  set_gdbarch_long_double_format    (gdbarch, floatformats_ieee_double);
  set_gdbarch_ptr_bit               (gdbarch, binfo->bits_per_address);
  set_gdbarch_ptr_bit               (gdbarch, binfo->bits_per_address);
  set_gdbarch_addr_bit              (gdbarch, binfo->bits_per_address);
  set_gdbarch_addr_bit              (gdbarch, binfo->bits_per_address);
  set_gdbarch_char_signed           (gdbarch, 1);
  set_gdbarch_char_signed           (gdbarch, 1);
 
 
  /* Information about the target architecture */
  /* Information about the target architecture */
  set_gdbarch_return_value          (gdbarch, or32_return_value);
  set_gdbarch_return_value          (gdbarch, or32_return_value);
  set_gdbarch_breakpoint_from_pc    (gdbarch, or32_breakpoint_from_pc);
  set_gdbarch_breakpoint_from_pc    (gdbarch, or32_breakpoint_from_pc);
  set_gdbarch_single_step_through_delay
  set_gdbarch_single_step_through_delay
                                    (gdbarch, or32_single_step_through_delay);
                                    (gdbarch, or32_single_step_through_delay);
  set_gdbarch_have_nonsteppable_watchpoint
  set_gdbarch_have_nonsteppable_watchpoint
                                    (gdbarch, 1);
                                    (gdbarch, 1);
  switch (gdbarch_byte_order (gdbarch))
  switch (gdbarch_byte_order (gdbarch))
    {
    {
    case BFD_ENDIAN_BIG:
    case BFD_ENDIAN_BIG:
      set_gdbarch_print_insn        (gdbarch, print_insn_big_or32);
      set_gdbarch_print_insn        (gdbarch, print_insn_big_or32);
      break;
      break;
 
 
    case BFD_ENDIAN_LITTLE:
    case BFD_ENDIAN_LITTLE:
      set_gdbarch_print_insn        (gdbarch, print_insn_little_or32);
      set_gdbarch_print_insn        (gdbarch, print_insn_little_or32);
      break;
      break;
 
 
    case BFD_ENDIAN_UNKNOWN:
    case BFD_ENDIAN_UNKNOWN:
      error ("or32_gdbarch_init: Unknown endianness");
      error ("or32_gdbarch_init: Unknown endianness");
      break;
      break;
    }
    }
 
 
  /* Register architecture */
  /* Register architecture */
  set_gdbarch_pseudo_register_read  (gdbarch, or32_pseudo_register_read);
  set_gdbarch_pseudo_register_read  (gdbarch, or32_pseudo_register_read);
  set_gdbarch_pseudo_register_write (gdbarch, or32_pseudo_register_write);
  set_gdbarch_pseudo_register_write (gdbarch, or32_pseudo_register_write);
  set_gdbarch_num_regs              (gdbarch, OR32_NUM_REGS);
  set_gdbarch_num_regs              (gdbarch, OR32_NUM_REGS);
  set_gdbarch_num_pseudo_regs       (gdbarch, OR32_NUM_PSEUDO_REGS);
  set_gdbarch_num_pseudo_regs       (gdbarch, OR32_NUM_PSEUDO_REGS);
  set_gdbarch_sp_regnum             (gdbarch, OR32_SP_REGNUM);
  set_gdbarch_sp_regnum             (gdbarch, OR32_SP_REGNUM);
  set_gdbarch_pc_regnum             (gdbarch, OR32_NPC_REGNUM);
  set_gdbarch_pc_regnum             (gdbarch, OR32_NPC_REGNUM);
  set_gdbarch_ps_regnum             (gdbarch, OR32_SR_REGNUM);
  set_gdbarch_ps_regnum             (gdbarch, OR32_SR_REGNUM);
  set_gdbarch_deprecated_fp_regnum  (gdbarch, OR32_FP_REGNUM);
  set_gdbarch_deprecated_fp_regnum  (gdbarch, OR32_FP_REGNUM);
 
 
  /* Functions to supply register information */
  /* Functions to supply register information */
  set_gdbarch_register_name         (gdbarch, or32_register_name);
  set_gdbarch_register_name         (gdbarch, or32_register_name);
  set_gdbarch_register_type         (gdbarch, or32_register_type);
  set_gdbarch_register_type         (gdbarch, or32_register_type);
  set_gdbarch_print_registers_info  (gdbarch, or32_registers_info);
  set_gdbarch_print_registers_info  (gdbarch, or32_registers_info);
  set_gdbarch_register_reggroup_p   (gdbarch, or32_register_reggroup_p);
  set_gdbarch_register_reggroup_p   (gdbarch, or32_register_reggroup_p);
 
 
  /* Functions to analyse frames */
  /* Functions to analyse frames */
  set_gdbarch_skip_prologue         (gdbarch, or32_skip_prologue);
  set_gdbarch_skip_prologue         (gdbarch, or32_skip_prologue);
  set_gdbarch_inner_than            (gdbarch, core_addr_lessthan);
  set_gdbarch_inner_than            (gdbarch, core_addr_lessthan);
  set_gdbarch_frame_align           (gdbarch, or32_frame_align);
  set_gdbarch_frame_align           (gdbarch, or32_frame_align);
  set_gdbarch_frame_red_zone_size   (gdbarch, OR32_FRAME_RED_ZONE_SIZE);
  set_gdbarch_frame_red_zone_size   (gdbarch, OR32_FRAME_RED_ZONE_SIZE);
 
 
  /* Functions to access frame data */
  /* Functions to access frame data */
  set_gdbarch_unwind_pc             (gdbarch, or32_unwind_pc);
  set_gdbarch_unwind_pc             (gdbarch, or32_unwind_pc);
  set_gdbarch_unwind_sp             (gdbarch, or32_unwind_sp);
  set_gdbarch_unwind_sp             (gdbarch, or32_unwind_sp);
 
 
  /* Functions handling dummy frames */
  /* Functions handling dummy frames */
  set_gdbarch_push_dummy_call       (gdbarch, or32_push_dummy_call);
  set_gdbarch_push_dummy_call       (gdbarch, or32_push_dummy_call);
  set_gdbarch_dummy_id              (gdbarch, or32_dummy_id);
  set_gdbarch_dummy_id              (gdbarch, or32_dummy_id);
 
 
  /* Set up sniffers for the frame base. Use DWARF debug info if available,
  /* Set up sniffers for the frame base. Use DWARF debug info if available,
     otherwise use our own sniffer. */
     otherwise use our own sniffer. */
  frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
  frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
  frame_base_append_sniffer (gdbarch, or32_frame_base_sniffer);
  frame_base_append_sniffer (gdbarch, or32_frame_base_sniffer);
 
 
  /* Frame unwinders. Use DWARF debug info if available, otherwise use our
  /* Frame unwinders. Use DWARF debug info if available, otherwise use our
     own unwinder. */
     own unwinder. */
  dwarf2_append_unwinders (gdbarch);
  dwarf2_append_unwinders (gdbarch);
  frame_unwind_append_unwinder (gdbarch, &or32_frame_unwind);
  frame_unwind_append_unwinder (gdbarch, &or32_frame_unwind);
 
 
  return gdbarch;
  return gdbarch;
 
 
}       /* or32_gdbarch_init() */
}       /* or32_gdbarch_init() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Dump the target specific data for this architecture
/*!Dump the target specific data for this architecture
 
 
   @param[in] gdbarch  The architecture of interest
   @param[in] gdbarch  The architecture of interest
   @param[in] file     Where to dump the data */
   @param[in] file     Where to dump the data */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or32_dump_tdep (struct gdbarch *gdbarch,
or32_dump_tdep (struct gdbarch *gdbarch,
                struct ui_file *file)
                struct ui_file *file)
{
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
 
  if (NULL == tdep)
  if (NULL == tdep)
    {
    {
      return;                   /* Nothing to report */
      return;                   /* Nothing to report */
    }
    }
 
 
  fprintf_unfiltered (file, "or32_dump_tdep: %d matchpoints available\n",
  fprintf_unfiltered (file, "or32_dump_tdep: %d matchpoints available\n",
                      tdep->num_matchpoints);
                      tdep->num_matchpoints);
  fprintf_unfiltered (file, "or32_dump_tdep: %d general purpose registers\n",
  fprintf_unfiltered (file, "or32_dump_tdep: %d general purpose registers\n",
                      tdep->num_gpr_regs);
                      tdep->num_gpr_regs);
  fprintf_unfiltered (file, "or32_dump_tdep: %d bytes per word\n",
  fprintf_unfiltered (file, "or32_dump_tdep: %d bytes per word\n",
                      tdep->bytes_per_word);
                      tdep->bytes_per_word);
  fprintf_unfiltered (file, "or32_dump_tdep: %d bytes per address\n",
  fprintf_unfiltered (file, "or32_dump_tdep: %d bytes per address\n",
                      tdep->bytes_per_address);
                      tdep->bytes_per_address);
 
 
}       /* or32_dump_tdep() */
}       /* or32_dump_tdep() */
 
 
 
 


/* Functions to add extra commands to GDB */
/* Functions to add extra commands to GDB */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Returns a special purpose register group name
/*!Returns a special purpose register group name
 
 
   @param[in]  group  The SPR group number
   @param[in]  group  The SPR group number
 
 
   @return  The SPR name (pointer to the name argument) */
   @return  The SPR name (pointer to the name argument) */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static const char *
static const char *
or32_spr_group_name (int  group)
or32_spr_group_name (int  group)
{
{
  static const char *or32_group_names[OR32_NUM_SPGS] =
  static const char *or32_group_names[OR32_NUM_SPGS] =
    {
    {
      "SYS",
      "SYS",
      "DMMU",
      "DMMU",
      "IMMU",
      "IMMU",
      "DCACHE",
      "DCACHE",
      "ICACHE",
      "ICACHE",
      "MAC",
      "MAC",
      "DEBUG",
      "DEBUG",
      "PERF",
      "PERF",
      "POWER",
      "POWER",
      "PIC",
      "PIC",
      "TIMER",
      "TIMER",
      "FPU"
      "FPU"
    };
    };
 
 
  if ((0 <= group) && (group < OR32_NUM_SPGS))
  if ((0 <= group) && (group < OR32_NUM_SPGS))
    {
    {
      return or32_group_names[group];
      return or32_group_names[group];
    }
    }
  else
  else
    {
    {
      return "";
      return "";
    }
    }
}       /* or32_spr_group_name() */
}       /* or32_spr_group_name() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Returns a special purpose register name
/*!Returns a special purpose register name
 
 
   @param[in]  group  The SPR group
   @param[in]  group  The SPR group
   @param[in]  index  The index within the SPR group
   @param[in]  index  The index within the SPR group
   @param[out] name   Array to put the name in
   @param[out] name   Array to put the name in
 
 
   @return  The SPR name (pointer to the name argument) */
   @return  The SPR name (pointer to the name argument) */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static char *
static char *
or32_spr_register_name (int   group,
or32_spr_register_name (int   group,
                        int   index,
                        int   index,
                        char *name)
                        char *name)
{
{
  char di;
  char di;
 
 
  switch (group)
  switch (group)
    {
    {
 
 
    case OR32_SPG_SYS:
    case OR32_SPG_SYS:
      /* 1:1 names */
      /* 1:1 names */
      switch (index)
      switch (index)
        {
        {
        case OR32_SPG_SYS_VR:       sprintf (name, "VR"      ); return  name;
        case OR32_SPG_SYS_VR:       sprintf (name, "VR"      ); return  name;
        case OR32_SPG_SYS_UPR:      sprintf (name, "UPR"     ); return  name;
        case OR32_SPG_SYS_UPR:      sprintf (name, "UPR"     ); return  name;
        case OR32_SPG_SYS_CPUCFGR:  sprintf (name, "CPUCFGR" ); return  name;
        case OR32_SPG_SYS_CPUCFGR:  sprintf (name, "CPUCFGR" ); return  name;
        case OR32_SPG_SYS_DMMUCFGR: sprintf (name, "DMMUCFGR"); return  name;
        case OR32_SPG_SYS_DMMUCFGR: sprintf (name, "DMMUCFGR"); return  name;
        case OR32_SPG_SYS_IMMUCFGR: sprintf (name, "IMMUCFGR"); return  name;
        case OR32_SPG_SYS_IMMUCFGR: sprintf (name, "IMMUCFGR"); return  name;
        case OR32_SPG_SYS_DCCFGR:   sprintf (name, "DCCFGR"  ); return  name;
        case OR32_SPG_SYS_DCCFGR:   sprintf (name, "DCCFGR"  ); return  name;
        case OR32_SPG_SYS_ICCFGR:   sprintf (name, "ICCFGR"  ); return  name;
        case OR32_SPG_SYS_ICCFGR:   sprintf (name, "ICCFGR"  ); return  name;
        case OR32_SPG_SYS_DCFGR:    sprintf (name, "DCFGR"   ); return  name;
        case OR32_SPG_SYS_DCFGR:    sprintf (name, "DCFGR"   ); return  name;
        case OR32_SPG_SYS_PCCFGR:   sprintf (name, "PCCFGR"  ); return  name;
        case OR32_SPG_SYS_PCCFGR:   sprintf (name, "PCCFGR"  ); return  name;
        case OR32_SPG_SYS_NPC:      sprintf (name, "NPC"     ); return  name;
        case OR32_SPG_SYS_NPC:      sprintf (name, "NPC"     ); return  name;
        case OR32_SPG_SYS_SR:       sprintf (name, "SR"      ); return  name;
        case OR32_SPG_SYS_SR:       sprintf (name, "SR"      ); return  name;
        case OR32_SPG_SYS_PPC:      sprintf (name, "PPC"     ); return  name;
        case OR32_SPG_SYS_PPC:      sprintf (name, "PPC"     ); return  name;
        case OR32_SPG_SYS_FPCSR:    sprintf (name, "FPCSR"   ); return  name;
        case OR32_SPG_SYS_FPCSR:    sprintf (name, "FPCSR"   ); return  name;
        }
        }
 
 
      /* Exception PC regs */
      /* Exception PC regs */
      if((OR32_SPG_SYS_EPCR <= index) &&
      if((OR32_SPG_SYS_EPCR <= index) &&
         (index             <= OR32_SPG_SYS_EPCR_END))
         (index             <= OR32_SPG_SYS_EPCR_END))
        {
        {
          sprintf (name, "EPCR%d", index - OR32_SPG_SYS_EPCR);
          sprintf (name, "EPCR%d", index - OR32_SPG_SYS_EPCR);
          return  name;
          return  name;
        }
        }
 
 
      /* Exception EA regs */
      /* Exception EA regs */
      if((OR32_SPG_SYS_EEAR <= index) &&
      if((OR32_SPG_SYS_EEAR <= index) &&
         (index             <= OR32_SPG_SYS_EEAR_END))
         (index             <= OR32_SPG_SYS_EEAR_END))
        {
        {
          sprintf (name, "EEAR%d", index - OR32_SPG_SYS_EEAR);
          sprintf (name, "EEAR%d", index - OR32_SPG_SYS_EEAR);
          return  name;
          return  name;
        }
        }
 
 
      /* Exception SR regs */
      /* Exception SR regs */
      if((OR32_SPG_SYS_ESR <= index) &&
      if((OR32_SPG_SYS_ESR <= index) &&
         (index            <= OR32_SPG_SYS_ESR_END))
         (index            <= OR32_SPG_SYS_ESR_END))
        {
        {
          sprintf (name, "ESR%d", index - OR32_SPG_SYS_ESR);
          sprintf (name, "ESR%d", index - OR32_SPG_SYS_ESR);
          return  name;
          return  name;
        }
        }
 
 
      /* GPRs */
      /* GPRs */
      if((OR32_SPG_SYS_GPR <= index) &&
      if((OR32_SPG_SYS_GPR <= index) &&
         (index            <= OR32_SPG_SYS_GPR_END))
         (index            <= OR32_SPG_SYS_GPR_END))
        {
        {
          sprintf (name, "GPR%d", index - OR32_SPG_SYS_GPR);
          sprintf (name, "GPR%d", index - OR32_SPG_SYS_GPR);
          return  name;
          return  name;
        }
        }
 
 
      break;
      break;
 
 
    case OR32_SPG_DMMU:
    case OR32_SPG_DMMU:
    case OR32_SPG_IMMU:
    case OR32_SPG_IMMU:
      /* MMU registers. Use DMMU constants throughout, but these are identical
      /* MMU registers. Use DMMU constants throughout, but these are identical
         to the corresponding IMMU constants */
         to the corresponding IMMU constants */
      di = OR32_SPG_DMMU == group ? 'D' : 'I';
      di = OR32_SPG_DMMU == group ? 'D' : 'I';
 
 
      /* 1:1 names */
      /* 1:1 names */
      switch (index)
      switch (index)
        {
        {
        case OR32_SPG_DMMU_DMMUCR:
        case OR32_SPG_DMMU_DMMUCR:
          sprintf (name, "%cMMUCR",  di); return  name;
          sprintf (name, "%cMMUCR",  di); return  name;
        case OR32_SPG_DMMU_DMMUPR:
        case OR32_SPG_DMMU_DMMUPR:
          sprintf (name, "%cMMUPR",  di); return  name;
          sprintf (name, "%cMMUPR",  di); return  name;
        case OR32_SPG_DMMU_DTLBEIR:
        case OR32_SPG_DMMU_DTLBEIR:
          sprintf (name, "%cTLBEIR", di); return  name;
          sprintf (name, "%cTLBEIR", di); return  name;
        }
        }
 
 
      /* ATB Match registers */
      /* ATB Match registers */
      if((OR32_SPG_DMMU_DATBMR <= index) &&
      if((OR32_SPG_DMMU_DATBMR <= index) &&
         (index                <= OR32_SPG_DMMU_DATBMR_END))
         (index                <= OR32_SPG_DMMU_DATBMR_END))
        {
        {
          sprintf (name, "%cATBMR%d", di, index - OR32_SPG_DMMU_DATBMR);
          sprintf (name, "%cATBMR%d", di, index - OR32_SPG_DMMU_DATBMR);
          return  name;
          return  name;
        }
        }
 
 
      /* ATB Translate registers */
      /* ATB Translate registers */
      if((OR32_SPG_DMMU_DATBTR <= index) &&
      if((OR32_SPG_DMMU_DATBTR <= index) &&
         (index                <= OR32_SPG_DMMU_DATBTR_END))
         (index                <= OR32_SPG_DMMU_DATBTR_END))
        {
        {
          sprintf (name, "%cATBTR%d", di, index - OR32_SPG_DMMU_DATBTR);
          sprintf (name, "%cATBTR%d", di, index - OR32_SPG_DMMU_DATBTR);
          return  name;
          return  name;
        }
        }
 
 
      /* TLB Way 1 Match registers */
      /* TLB Way 1 Match registers */
      if((OR32_SPG_DMMU_DTLBW1MR <= index) &&
      if((OR32_SPG_DMMU_DTLBW1MR <= index) &&
         (index                <= OR32_SPG_DMMU_DTLBW1MR_END))
         (index                <= OR32_SPG_DMMU_DTLBW1MR_END))
        {
        {
          sprintf (name, "%cTLBW1MR%d", di, index - OR32_SPG_DMMU_DTLBW1MR);
          sprintf (name, "%cTLBW1MR%d", di, index - OR32_SPG_DMMU_DTLBW1MR);
          return  name;
          return  name;
        }
        }
 
 
      /* TLB Way 1 Translate registers */
      /* TLB Way 1 Translate registers */
      if((OR32_SPG_DMMU_DTLBW1TR <= index) &&
      if((OR32_SPG_DMMU_DTLBW1TR <= index) &&
         (index                <= OR32_SPG_DMMU_DTLBW1TR_END))
         (index                <= OR32_SPG_DMMU_DTLBW1TR_END))
        {
        {
          sprintf (name, "%cTLBW1TR%d", di, index - OR32_SPG_DMMU_DTLBW1TR);
          sprintf (name, "%cTLBW1TR%d", di, index - OR32_SPG_DMMU_DTLBW1TR);
          return  name;
          return  name;
        }
        }
 
 
      /* TLB Way 2 Match registers */
      /* TLB Way 2 Match registers */
      if((OR32_SPG_DMMU_DTLBW2MR <= index) &&
      if((OR32_SPG_DMMU_DTLBW2MR <= index) &&
         (index                <= OR32_SPG_DMMU_DTLBW2MR_END))
         (index                <= OR32_SPG_DMMU_DTLBW2MR_END))
        {
        {
          sprintf (name, "%cTLBW2MR%d", di, index - OR32_SPG_DMMU_DTLBW2MR);
          sprintf (name, "%cTLBW2MR%d", di, index - OR32_SPG_DMMU_DTLBW2MR);
          return  name;
          return  name;
        }
        }
 
 
      /* TLB Way 2 Translate registers */
      /* TLB Way 2 Translate registers */
      if((OR32_SPG_DMMU_DTLBW2TR <= index) &&
      if((OR32_SPG_DMMU_DTLBW2TR <= index) &&
         (index                <= OR32_SPG_DMMU_DTLBW2TR_END))
         (index                <= OR32_SPG_DMMU_DTLBW2TR_END))
        {
        {
          sprintf (name, "%cTLBW2TR%d", di, index - OR32_SPG_DMMU_DTLBW2TR);
          sprintf (name, "%cTLBW2TR%d", di, index - OR32_SPG_DMMU_DTLBW2TR);
          return  name;
          return  name;
        }
        }
 
 
      /* TLB Way 3 Match registers */
      /* TLB Way 3 Match registers */
      if((OR32_SPG_DMMU_DTLBW3MR <= index) &&
      if((OR32_SPG_DMMU_DTLBW3MR <= index) &&
         (index                <= OR32_SPG_DMMU_DTLBW3MR_END))
         (index                <= OR32_SPG_DMMU_DTLBW3MR_END))
        {
        {
          sprintf (name, "%cTLBW3MR%d", di, index - OR32_SPG_DMMU_DTLBW3MR);
          sprintf (name, "%cTLBW3MR%d", di, index - OR32_SPG_DMMU_DTLBW3MR);
          return  name;
          return  name;
        }
        }
 
 
      /* TLB Way 3 Translate registers */
      /* TLB Way 3 Translate registers */
      if((OR32_SPG_DMMU_DTLBW3TR <= index) &&
      if((OR32_SPG_DMMU_DTLBW3TR <= index) &&
         (index                <= OR32_SPG_DMMU_DTLBW3TR_END))
         (index                <= OR32_SPG_DMMU_DTLBW3TR_END))
        {
        {
          sprintf (name, "%cTLBW3TR%d", di, index - OR32_SPG_DMMU_DTLBW3TR);
          sprintf (name, "%cTLBW3TR%d", di, index - OR32_SPG_DMMU_DTLBW3TR);
          return  name;
          return  name;
        }
        }
 
 
      break;
      break;
 
 
    case OR32_SPG_DC:
    case OR32_SPG_DC:
      /* Data cache registers. These do not have an exact correspondence with
      /* Data cache registers. These do not have an exact correspondence with
         their instruction cache counterparts, so must be done separately. */
         their instruction cache counterparts, so must be done separately. */
 
 
      /* 1:1 names */
      /* 1:1 names */
      switch (index)
      switch (index)
        {
        {
        case OR32_SPG_DC_DCCR:  sprintf (name, "DCCR" ); return  name;
        case OR32_SPG_DC_DCCR:  sprintf (name, "DCCR" ); return  name;
        case OR32_SPG_DC_DCBPR: sprintf (name, "DCBPR"); return  name;
        case OR32_SPG_DC_DCBPR: sprintf (name, "DCBPR"); return  name;
        case OR32_SPG_DC_DCBFR: sprintf (name, "DCBFR"); return  name;
        case OR32_SPG_DC_DCBFR: sprintf (name, "DCBFR"); return  name;
        case OR32_SPG_DC_DCBIR: sprintf (name, "DCBIR"); return  name;
        case OR32_SPG_DC_DCBIR: sprintf (name, "DCBIR"); return  name;
        case OR32_SPG_DC_DCBWR: sprintf (name, "DCBWR"); return  name;
        case OR32_SPG_DC_DCBWR: sprintf (name, "DCBWR"); return  name;
        case OR32_SPG_DC_DCBLR: sprintf (name, "DCBLR"); return  name;
        case OR32_SPG_DC_DCBLR: sprintf (name, "DCBLR"); return  name;
        }
        }
 
 
      break;
      break;
 
 
    case OR32_SPG_IC:
    case OR32_SPG_IC:
      /* Instruction cache registers */
      /* Instruction cache registers */
 
 
      /* 1:1 names */
      /* 1:1 names */
      switch (index)
      switch (index)
        {
        {
        case OR32_SPG_IC_ICCR:  sprintf (name, "ICCR" ); return  name;
        case OR32_SPG_IC_ICCR:  sprintf (name, "ICCR" ); return  name;
        case OR32_SPG_IC_ICBPR: sprintf (name, "ICBPR"); return  name;
        case OR32_SPG_IC_ICBPR: sprintf (name, "ICBPR"); return  name;
        case OR32_SPG_IC_ICBIR: sprintf (name, "ICBIR"); return  name;
        case OR32_SPG_IC_ICBIR: sprintf (name, "ICBIR"); return  name;
        case OR32_SPG_IC_ICBLR: sprintf (name, "ICBLR"); return  name;
        case OR32_SPG_IC_ICBLR: sprintf (name, "ICBLR"); return  name;
        }
        }
 
 
      break;
      break;
 
 
    case OR32_SPG_MAC:
    case OR32_SPG_MAC:
      /* MAC registers */
      /* MAC registers */
 
 
      /* 1:1 names */
      /* 1:1 names */
      switch (index)
      switch (index)
        {
        {
        case OR32_SPG_MAC_MACLO: sprintf (name, "MACLO"); return  name;
        case OR32_SPG_MAC_MACLO: sprintf (name, "MACLO"); return  name;
        case OR32_SPG_MAC_MACHI: sprintf (name, "MACHI"); return  name;
        case OR32_SPG_MAC_MACHI: sprintf (name, "MACHI"); return  name;
        }
        }
 
 
      break;
      break;
 
 
    case OR32_SPG_DEBUG:
    case OR32_SPG_DEBUG:
      /* Debug registers */
      /* Debug registers */
 
 
      /* Debug Value registers */
      /* Debug Value registers */
      if((OR32_SPG_DEBUG_DVR <= index) &&
      if((OR32_SPG_DEBUG_DVR <= index) &&
         (index                <= OR32_SPG_DEBUG_DVR_END))
         (index                <= OR32_SPG_DEBUG_DVR_END))
        {
        {
          sprintf (name, "DVR%d", index - OR32_SPG_DEBUG_DVR);
          sprintf (name, "DVR%d", index - OR32_SPG_DEBUG_DVR);
          return  name;
          return  name;
        }
        }
 
 
      /* Debug Control registers */
      /* Debug Control registers */
      if((OR32_SPG_DEBUG_DCR <= index) &&
      if((OR32_SPG_DEBUG_DCR <= index) &&
         (index                <= OR32_SPG_DEBUG_DCR_END))
         (index                <= OR32_SPG_DEBUG_DCR_END))
        {
        {
          sprintf (name, "DCR%d", index - OR32_SPG_DEBUG_DCR);
          sprintf (name, "DCR%d", index - OR32_SPG_DEBUG_DCR);
          return  name;
          return  name;
        }
        }
 
 
      /* 1:1 names */
      /* 1:1 names */
      switch (index)
      switch (index)
        {
        {
        case OR32_SPG_DEBUG_DMR1:  sprintf (name, "DMR1" ); return  name;
        case OR32_SPG_DEBUG_DMR1:  sprintf (name, "DMR1" ); return  name;
        case OR32_SPG_DEBUG_DMR2:  sprintf (name, "DMR2" ); return  name;
        case OR32_SPG_DEBUG_DMR2:  sprintf (name, "DMR2" ); return  name;
        case OR32_SPG_DEBUG_DCWR0: sprintf (name, "DCWR0"); return  name;
        case OR32_SPG_DEBUG_DCWR0: sprintf (name, "DCWR0"); return  name;
        case OR32_SPG_DEBUG_DCWR1: sprintf (name, "DCWR1"); return  name;
        case OR32_SPG_DEBUG_DCWR1: sprintf (name, "DCWR1"); return  name;
        case OR32_SPG_DEBUG_DSR:   sprintf (name, "DSR"  ); return  name;
        case OR32_SPG_DEBUG_DSR:   sprintf (name, "DSR"  ); return  name;
        case OR32_SPG_DEBUG_DRR:   sprintf (name, "DRR"  ); return  name;
        case OR32_SPG_DEBUG_DRR:   sprintf (name, "DRR"  ); return  name;
        }
        }
 
 
      break;
      break;
 
 
    case OR32_SPG_PC:
    case OR32_SPG_PC:
      /* Performance Counter registers */
      /* Performance Counter registers */
 
 
      /* Performance Counters Count registers */
      /* Performance Counters Count registers */
      if((OR32_SPG_PC_PCCR <= index) &&
      if((OR32_SPG_PC_PCCR <= index) &&
         (index                <= OR32_SPG_PC_PCCR_END))
         (index                <= OR32_SPG_PC_PCCR_END))
        {
        {
          sprintf (name, "PCCR%d", index - OR32_SPG_PC_PCCR);
          sprintf (name, "PCCR%d", index - OR32_SPG_PC_PCCR);
          return  name;
          return  name;
        }
        }
 
 
      /* Performance Counters Mode registers */
      /* Performance Counters Mode registers */
      if((OR32_SPG_PC_PCMR <= index) &&
      if((OR32_SPG_PC_PCMR <= index) &&
         (index                <= OR32_SPG_PC_PCMR_END))
         (index                <= OR32_SPG_PC_PCMR_END))
        {
        {
          sprintf (name, "PCMR%d", index - OR32_SPG_PC_PCMR);
          sprintf (name, "PCMR%d", index - OR32_SPG_PC_PCMR);
          return  name;
          return  name;
        }
        }
 
 
      break;
      break;
 
 
    case OR32_SPG_PM:
    case OR32_SPG_PM:
      /* Power Management registers */
      /* Power Management registers */
 
 
      /* 1:1 names */
      /* 1:1 names */
      switch (index)
      switch (index)
        {
        {
        case OR32_SPG_PM_PMR:  sprintf (name, "PMR"); return  name;
        case OR32_SPG_PM_PMR:  sprintf (name, "PMR"); return  name;
        }
        }
 
 
      break;
      break;
 
 
    case OR32_SPG_PIC:
    case OR32_SPG_PIC:
      /* Programmable Interrupt Controller registers */
      /* Programmable Interrupt Controller registers */
 
 
      /* 1:1 names */
      /* 1:1 names */
      switch (index)
      switch (index)
        {
        {
        case OR32_SPG_PIC_PICMR:  sprintf (name, "PICMR"); return  name;
        case OR32_SPG_PIC_PICMR:  sprintf (name, "PICMR"); return  name;
        case OR32_SPG_PIC_PICSR:  sprintf (name, "PICSR"); return  name;
        case OR32_SPG_PIC_PICSR:  sprintf (name, "PICSR"); return  name;
        }
        }
 
 
      break;
      break;
 
 
    case OR32_SPG_TT:
    case OR32_SPG_TT:
      /* Tick Timer registers */
      /* Tick Timer registers */
 
 
      /* 1:1 names */
      /* 1:1 names */
      switch (index)
      switch (index)
        {
        {
        case OR32_SPG_TT_TTMR:  sprintf (name, "TTMR"); return  name;
        case OR32_SPG_TT_TTMR:  sprintf (name, "TTMR"); return  name;
        case OR32_SPG_TT_TTCR:  sprintf (name, "TTCR"); return  name;
        case OR32_SPG_TT_TTCR:  sprintf (name, "TTCR"); return  name;
        }
        }
 
 
      break;
      break;
 
 
    case OR32_SPG_FPU:
    case OR32_SPG_FPU:
 
 
      break;
      break;
    }
    }
 
 
  /* Not a recognized register */
  /* Not a recognized register */
  strcpy (name, "");
  strcpy (name, "");
  return  name;
  return  name;
 
 
}       /* or32_spr_register_name() */
}       /* or32_spr_register_name() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Get SPR group number from a name
/*!Get SPR group number from a name
 
 
   @param[in] group_name  SPR register group
   @param[in] group_name  SPR register group
 
 
   @return  The index, or negative if no match. */
   @return  The index, or negative if no match. */
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
 
 
static int
static int
or32_groupnum_from_name (char *group_name)
or32_groupnum_from_name (char *group_name)
{
{
  int  group;
  int  group;
 
 
  for (group = 0; group < OR32_NUM_SPGS; group++)
  for (group = 0; group < OR32_NUM_SPGS; group++)
    {
    {
      if (0 == strcasecmp (group_name, or32_spr_group_name (group)))
      if (0 == strcasecmp (group_name, or32_spr_group_name (group)))
        {
        {
          return group;
          return group;
        }
        }
    }
    }
 
 
  return -1;
  return -1;
 
 
}       /* or32_groupnum_from_name() */
}       /* or32_groupnum_from_name() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Get register index in special purpose register group from name
/*!Get register index in special purpose register group from name
 
 
   The name may either be SPR<group_num>_<index> or a known unique name. In
   The name may either be SPR<group_num>_<index> or a known unique name. In
   either case the group number must match the supplied group number.
   either case the group number must match the supplied group number.
 
 
   @param[in] group  SPR register group
   @param[in] group  SPR register group
   @param[in] name   Register name
   @param[in] name   Register name
 
 
   @return  The index, or negative if no match. */
   @return  The index, or negative if no match. */
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
 
 
static int
static int
or32_regnum_from_name (int   group,
or32_regnum_from_name (int   group,
                       char *name)
                       char *name)
{
{
  /* Last valid register in each group. */
  /* Last valid register in each group. */
  static const int  or32_spr_group_last[OR32_NUM_SPGS] =
  static const int  or32_spr_group_last[OR32_NUM_SPGS] =
    {
    {
      OR32_SPG_SYS_LAST,
      OR32_SPG_SYS_LAST,
      OR32_SPG_DMMU_LAST,
      OR32_SPG_DMMU_LAST,
      OR32_SPG_IMMU_LAST,
      OR32_SPG_IMMU_LAST,
      OR32_SPG_DC_LAST,
      OR32_SPG_DC_LAST,
      OR32_SPG_IC_LAST,
      OR32_SPG_IC_LAST,
      OR32_SPG_MAC_LAST,
      OR32_SPG_MAC_LAST,
      OR32_SPG_DEBUG_LAST,
      OR32_SPG_DEBUG_LAST,
      OR32_SPG_PC_LAST,
      OR32_SPG_PC_LAST,
      OR32_SPG_PM_LAST,
      OR32_SPG_PM_LAST,
      OR32_SPG_PIC_LAST,
      OR32_SPG_PIC_LAST,
      OR32_SPG_TT_LAST,
      OR32_SPG_TT_LAST,
      OR32_SPG_FPU_LAST
      OR32_SPG_FPU_LAST
    };
    };
 
 
  int  i;
  int  i;
  char  spr_name[32];
  char  spr_name[32];
 
 
  if (0 == strcasecmp (name, "SPR"))
  if (0 == strcasecmp (name, "SPR"))
    {
    {
      char *ptr_c;
      char *ptr_c;
 
 
      /* Skip SPR */
      /* Skip SPR */
      name += 3;
      name += 3;
 
 
      /* Get group number */
      /* Get group number */
      i = (int) strtoul (name, &ptr_c, 10);
      i = (int) strtoul (name, &ptr_c, 10);
      if (*ptr_c != '_' || i != group)
      if (*ptr_c != '_' || i != group)
        {
        {
          return -1;
          return -1;
        }
        }
 
 
      /* Get index */
      /* Get index */
      ptr_c++;
      ptr_c++;
      i = (int) strtoul (name, &ptr_c, 10);
      i = (int) strtoul (name, &ptr_c, 10);
      if (*ptr_c)
      if (*ptr_c)
        {
        {
          return -1;
          return -1;
        }
        }
      else
      else
        {
        {
          return  i;
          return  i;
        }
        }
    }
    }
 
 
  /* Look for a "known" name in this group */
  /* Look for a "known" name in this group */
  for (i = 0; i <= or32_spr_group_last[group]; i++)
  for (i = 0; i <= or32_spr_group_last[group]; i++)
    {
    {
      char *s = or32_spr_register_name (group, i, spr_name);
      char *s = or32_spr_register_name (group, i, spr_name);
 
 
      if (0 == strcasecmp (name, s))
      if (0 == strcasecmp (name, s))
        {
        {
          return i;
          return i;
        }
        }
    }
    }
 
 
  /* Failure */
  /* Failure */
  return -1;
  return -1;
 
 
}       /* or32_regnum_from_name() */
}       /* or32_regnum_from_name() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Get the next token from a string
/*!Get the next token from a string
 
 
   I can't believe there isn't a library argument for this, but strtok is
   I can't believe there isn't a library argument for this, but strtok is
   deprecated.
   deprecated.
 
 
   Take a string and find the start of the next token and its length. A token
   Take a string and find the start of the next token and its length. A token
   is anything containing non-blank characters.
   is anything containing non-blank characters.
 
 
   @param[in]  str  The string to look at (may be NULL).
   @param[in]  str  The string to look at (may be NULL).
   @param[out] tok  Pointer to the start of the token within str. May be NULL
   @param[out] tok  Pointer to the start of the token within str. May be NULL
                    if this result is not wanted (e.g. just the length is
                    if this result is not wanted (e.g. just the length is
                    wanted. If no token is found will be the NULL char at the
                    wanted. If no token is found will be the NULL char at the
                    end of the string, if the original str was NULL, this will
                    end of the string, if the original str was NULL, this will
                    be NULL.
                    be NULL.
 
 
                    @return  The length of the token found */
                    @return  The length of the token found */
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
 
 
static int
static int
or32_tokenize (char  *str,
or32_tokenize (char  *str,
               char **tok)
               char **tok)
{
{
  char *ptr;
  char *ptr;
  int   len;
  int   len;
 
 
  /* Deal with NULL argument */
  /* Deal with NULL argument */
  if (NULL == str)
  if (NULL == str)
    {
    {
      if (NULL != tok)
      if (NULL != tok)
        {
        {
          *tok = NULL;
          *tok = NULL;
        }
        }
      return 0;
      return 0;
    }
    }
 
 
  /* Find the start */
  /* Find the start */
  for (ptr = str; ISBLANK (*ptr) ; ptr++)
  for (ptr = str; ISBLANK (*ptr) ; ptr++)
    {
    {
      continue;
      continue;
    }
    }
 
 
  /* Return the start pointer if requested */
  /* Return the start pointer if requested */
  if (NULL != tok)
  if (NULL != tok)
    {
    {
      *tok = ptr;
      *tok = ptr;
    }
    }
 
 
  /* Find the end and put in EOS */
  /* Find the end and put in EOS */
  for (len = 0;  ('\0' != ptr[len]) && (!ISBLANK (ptr[len])); len++)
  for (len = 0;  ('\0' != ptr[len]) && (!ISBLANK (ptr[len])); len++)
    {
    {
      continue;
      continue;
    }
    }
 
 
  return len;
  return len;
 
 
}       /* or32_tokenize() */
}       /* or32_tokenize() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Parses args for spr commands
/*!Parses args for spr commands
 
 
   Determines the special purpose register (SPR) name and puts result into
   Determines the special purpose register (SPR) name and puts result into
   group and index
   group and index
 
 
   Syntax is:
   Syntax is:
 
 
   @verbatim
   @verbatim
   <spr_args>    -> <group_ref> | <reg_name>
   <spr_args>    -> <group_ref> | <reg_name>
   <group_ref>   -> <group_id> <index>
   <group_ref>   -> <group_id> <index>
   <group_id>    -> <group_num> | <group_name>
   <group_id>    -> <group_num> | <group_name>
   @endverbatim
   @endverbatim
 
 
   Where the indices/names have to be valid.
   Where the indices/names have to be valid.
 
 
   So to parse, we look for 1 or 2 args. If 1 it must be a unique register
   So to parse, we look for 1 or 2 args. If 1 it must be a unique register
   name. If 2, the first must be a group number or name and the second an
   name. If 2, the first must be a group number or name and the second an
   index within that group.
   index within that group.
 
 
   Also responsible for providing diagnostics if the arguments do not match.
   Also responsible for providing diagnostics if the arguments do not match.
 
 
   Rewritten for GDB 6.8 to use the new UI calls and remove assorted
   Rewritten for GDB 6.8 to use the new UI calls and remove assorted
   bugs. Syntax also slightly restricted to be more comprehensible.
   bugs. Syntax also slightly restricted to be more comprehensible.
 
 
   @param[in]  arg_str  The argument string
   @param[in]  arg_str  The argument string
   @param[out] group    The group this SPR belongs in, or -1 to indicate
   @param[out] group    The group this SPR belongs in, or -1 to indicate
                        failure
                        failure
   @param[out] index    Index of the register within the group, or -1 to
   @param[out] index    Index of the register within the group, or -1 to
                        indicate the whole group
                        indicate the whole group
   @param[in]  is_set   1 (true) if we are called from the "spr" command (so
   @param[in]  is_set   1 (true) if we are called from the "spr" command (so
                        there is an extra arg) rather than the "info spr"
                        there is an extra arg) rather than the "info spr"
                        command. Needed to distinguish between the case where
                        command. Needed to distinguish between the case where
                        info is sought from a register specified as group and
                        info is sought from a register specified as group and
                        index and setting a uniquely identified register to a
                        index and setting a uniquely identified register to a
                        value.
                        value.
 
 
                        @return  A pointer to any remaining args */
                        @return  A pointer to any remaining args */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static char *
static char *
or32_parse_spr_params (char *arg_str,
or32_parse_spr_params (char *arg_str,
                       int  *group,
                       int  *group,
                       int  *index,
                       int  *index,
                       int   is_set)
                       int   is_set)
{
{
  struct {
  struct {
    char              *str;
    char              *str;
    int                len;
    int                len;
    unsigned long int  val;
    unsigned long int  val;
    int                is_num;
    int                is_num;
  } arg[3] = {
  } arg[3] = {
    {
    {
      .str    = NULL,
      .str    = NULL,
      .len    = 0,
      .len    = 0,
      .val    = 0,
      .val    = 0,
      .is_num = 0,
      .is_num = 0,
    },
    },
   {
   {
      .str    = NULL,
      .str    = NULL,
      .len    = 0,
      .len    = 0,
      .val    = 0,
      .val    = 0,
      .is_num = 0,
      .is_num = 0,
    },
    },
   {
   {
      .str    = NULL,
      .str    = NULL,
      .len    = 0,
      .len    = 0,
      .val    = 0,
      .val    = 0,
      .is_num = 0,
      .is_num = 0,
    }
    }
  };
  };
 
 
  int   num_args;
  int   num_args;
  char *trailer  = arg_str;
  char *trailer  = arg_str;
  char *tmp_str;
  char *tmp_str;
  int   i;
  int   i;
 
 
  char  spr_name[32];
  char  spr_name[32];
 
 
  /* Break out the arguments. Note that the strings are NOT null terminated
  /* Break out the arguments. Note that the strings are NOT null terminated
     (we don't want to change arg_str), so we must rely on len. The stroul
     (we don't want to change arg_str), so we must rely on len. The stroul
     call will still work, since there is always a non-digit char (possibly EOS)
     call will still work, since there is always a non-digit char (possibly EOS)
     after the last digit. */
     after the last digit. */
  if (NULL == arg_str)
  if (NULL == arg_str)
    {
    {
      num_args = 0;
      num_args = 0;
    }
    }
  else
  else
    {
    {
      for (num_args = 0; num_args < 3; num_args++)
      for (num_args = 0; num_args < 3; num_args++)
        {
        {
          arg[num_args].len = or32_tokenize (trailer, &(arg[num_args].str));
          arg[num_args].len = or32_tokenize (trailer, &(arg[num_args].str));
          trailer           = arg[num_args].str + arg[num_args].len;
          trailer           = arg[num_args].str + arg[num_args].len;
 
 
          if (0 == arg[num_args].len)
          if (0 == arg[num_args].len)
            {
            {
              break;
              break;
            }
            }
        }
        }
    }
    }
 
 
  /* Patch nulls into the arg strings and see about values. Couldn't do this
  /* Patch nulls into the arg strings and see about values. Couldn't do this
     earlier, since we needed the next char clean to check later args. This
     earlier, since we needed the next char clean to check later args. This
     means advancing trailer, UNLESS it was already at EOS */
     means advancing trailer, UNLESS it was already at EOS */
 
 
  if((NULL != arg_str) && ('\0' != *trailer))
  if((NULL != arg_str) && ('\0' != *trailer))
    {
    {
      trailer++;
      trailer++;
    }
    }
 
 
  for (i = 0; i < num_args; i++)
  for (i = 0; i < num_args; i++)
    {
    {
      (arg[i].str)[arg[i].len] = '\0';
      (arg[i].str)[arg[i].len] = '\0';
      errno                    = 0;
      errno                    = 0;
      arg[i].val               = strtoul (arg[i].str, &tmp_str, 0);
      arg[i].val               = strtoul (arg[i].str, &tmp_str, 0);
      arg[i].is_num            = (0 == errno) && ('\0' == *tmp_str);
      arg[i].is_num            = (0 == errno) && ('\0' == *tmp_str);
    }
    }
 
 
  /* Deal with the case where we are setting a register, so the final argument
  /* Deal with the case where we are setting a register, so the final argument
     should be disregarded (it is the trailer). Do this anyway if we get a
     should be disregarded (it is the trailer). Do this anyway if we get a
     third argument */
     third argument */
  if ((is_set & (num_args > 0)) || (num_args > 2))
  if ((is_set & (num_args > 0)) || (num_args > 2))
    {
    {
      trailer = arg[num_args - 1].str;
      trailer = arg[num_args - 1].str;
      num_args--;
      num_args--;
    }
    }
 
 
  /* Deal with different numbers of args */
  /* Deal with different numbers of args */
 
 
  switch (num_args)
  switch (num_args)
    {
    {
 
 
    case 0:
    case 0:
      ui_out_message (uiout, 0,
      ui_out_message (uiout, 0,
                      "Usage: <command> <register>      |\n"
                      "Usage: <command> <register>      |\n"
                      "       <command> <group>         |\n"
                      "       <command> <group>         |\n"
                      "       <command> <group> <index>\n"
                      "       <command> <group> <index>\n"
                      "Valid groups are:\n");
                      "Valid groups are:\n");
      for (i = 0; i < OR32_NUM_SPGS; i++)
      for (i = 0; i < OR32_NUM_SPGS; i++)
        {
        {
          ui_out_field_string (uiout, NULL, or32_spr_group_name  (i));
          ui_out_field_string (uiout, NULL, or32_spr_group_name  (i));
          ui_out_spaces (uiout, 1);
          ui_out_spaces (uiout, 1);
          ui_out_wrap_hint (uiout, NULL);
          ui_out_wrap_hint (uiout, NULL);
        }
        }
      ui_out_field_string (uiout, NULL, "\n");
      ui_out_field_string (uiout, NULL, "\n");
 
 
      *index = -1;
      *index = -1;
      return  trailer;
      return  trailer;
 
 
    case 1:
    case 1:
      /* See if it is a numeric group */
      /* See if it is a numeric group */
      if (arg[0].is_num)
      if (arg[0].is_num)
        {
        {
          if (arg[0].val < OR32_NUM_SPGS)
          if (arg[0].val < OR32_NUM_SPGS)
            {
            {
              *group = arg[0].val;
              *group = arg[0].val;
              *index = -1;
              *index = -1;
              return trailer;
              return trailer;
            }
            }
          else
          else
            {
            {
              ui_out_message (uiout, 0,
              ui_out_message (uiout, 0,
                              "Group index should be in the range 0 - %d\n",
                              "Group index should be in the range 0 - %d\n",
                              OR32_NUM_SPGS);
                              OR32_NUM_SPGS);
              *group = -1;
              *group = -1;
              *index = -1;
              *index = -1;
              return trailer;
              return trailer;
            }
            }
        }
        }
 
 
      /* Is is it a group name? */
      /* Is is it a group name? */
      *group = or32_groupnum_from_name (arg[0].str);
      *group = or32_groupnum_from_name (arg[0].str);
      if (*group >= 0)
      if (*group >= 0)
        {
        {
          *index = -1;
          *index = -1;
          return trailer;
          return trailer;
        }
        }
 
 
      /* See if it is a valid register name in any group */
      /* See if it is a valid register name in any group */
      for (*group = 0; *group < OR32_NUM_SPGS; (*group)++)
      for (*group = 0; *group < OR32_NUM_SPGS; (*group)++)
        {
        {
          *index = or32_regnum_from_name (*group, arg[0].str);
          *index = or32_regnum_from_name (*group, arg[0].str);
 
 
          if (*index >= 0)
          if (*index >= 0)
            {
            {
              return  trailer;
              return  trailer;
            }
            }
        }
        }
 
 
      /* Couldn't find it - print out a rude message */
      /* Couldn't find it - print out a rude message */
      ui_out_message (uiout, 0,
      ui_out_message (uiout, 0,
                      "Group or register name not recognized.\n"
                      "Group or register name not recognized.\n"
                      "Valid groups are:\n");
                      "Valid groups are:\n");
      for (i = 0; i < OR32_NUM_SPGS; i++)
      for (i = 0; i < OR32_NUM_SPGS; i++)
        {
        {
          ui_out_field_string (uiout, NULL, or32_spr_group_name (i));
          ui_out_field_string (uiout, NULL, or32_spr_group_name (i));
          ui_out_spaces (uiout, 1);
          ui_out_spaces (uiout, 1);
          ui_out_wrap_hint (uiout, NULL);
          ui_out_wrap_hint (uiout, NULL);
        }
        }
      ui_out_field_string (uiout, NULL, "\n");
      ui_out_field_string (uiout, NULL, "\n");
 
 
      *group = -1;
      *group = -1;
      *index = -1;
      *index = -1;
      return  trailer;
      return  trailer;
 
 
    case 2:
    case 2:
      /* See if first arg is a numeric group */
      /* See if first arg is a numeric group */
      if (arg[0].is_num)
      if (arg[0].is_num)
        {
        {
          if (arg[0].val < OR32_NUM_SPGS)
          if (arg[0].val < OR32_NUM_SPGS)
            {
            {
              *group = arg[0].val;
              *group = arg[0].val;
              *index = -1;
              *index = -1;
            }
            }
          else
          else
            {
            {
              ui_out_message (uiout, 0,
              ui_out_message (uiout, 0,
                              "Group index should be in the range 0 - %d\n",
                              "Group index should be in the range 0 - %d\n",
                              OR32_NUM_SPGS - 1);
                              OR32_NUM_SPGS - 1);
              *group = -1;
              *group = -1;
              *index = -1;
              *index = -1;
              return trailer;
              return trailer;
            }
            }
        }
        }
      else
      else
        {
        {
          /* Is is it a group name? */
          /* Is is it a group name? */
          *group = or32_groupnum_from_name (arg[0].str);
          *group = or32_groupnum_from_name (arg[0].str);
          if (*group >= 0)
          if (*group >= 0)
            {
            {
              *index = -1;
              *index = -1;
            }
            }
          else
          else
            {
            {
              ui_out_message (uiout, 0,
              ui_out_message (uiout, 0,
                              "Group name not recognized.\n"
                              "Group name not recognized.\n"
                              "Valid groups are:\n");
                              "Valid groups are:\n");
              for (i = 0; i < OR32_NUM_SPGS; i++)
              for (i = 0; i < OR32_NUM_SPGS; i++)
                {
                {
                  ui_out_field_string (uiout, NULL, or32_spr_group_name (i));
                  ui_out_field_string (uiout, NULL, or32_spr_group_name (i));
                  ui_out_spaces (uiout, 1);
                  ui_out_spaces (uiout, 1);
                  ui_out_wrap_hint (uiout, NULL);
                  ui_out_wrap_hint (uiout, NULL);
                }
                }
              ui_out_field_string (uiout, NULL, "\n");
              ui_out_field_string (uiout, NULL, "\n");
 
 
              *group = -1;
              *group = -1;
              *index = -1;
              *index = -1;
              return  trailer;
              return  trailer;
            }
            }
        }
        }
 
 
      /* Is second arg an index or name? */
      /* Is second arg an index or name? */
      if (arg[1].is_num)
      if (arg[1].is_num)
        {
        {
          if (arg[1].val < OR32_SPG_SIZE)
          if (arg[1].val < OR32_SPG_SIZE)
            {
            {
              /* Check this really is a register */
              /* Check this really is a register */
              if (0 != strlen (or32_spr_register_name (*group, arg[1].val,
              if (0 != strlen (or32_spr_register_name (*group, arg[1].val,
                                                       spr_name)))
                                                       spr_name)))
                {
                {
                  *index = arg[1].val;
                  *index = arg[1].val;
                  return trailer;
                  return trailer;
                }
                }
              else
              else
                {
                {
                  ui_out_message (uiout, 0,
                  ui_out_message (uiout, 0,
                                  "No valid register at that index in group\n");
                                  "No valid register at that index in group\n");
                  *group = -1;
                  *group = -1;
                  *index = -1;
                  *index = -1;
                  return  trailer;
                  return  trailer;
                }
                }
            }
            }
          else
          else
            {
            {
              ui_out_message (uiout, 0,
              ui_out_message (uiout, 0,
                              "Register index should be in the range 0 - %d\n",
                              "Register index should be in the range 0 - %d\n",
                              OR32_SPG_SIZE - 1);
                              OR32_SPG_SIZE - 1);
              *group = -1;
              *group = -1;
              *index = -1;
              *index = -1;
              return  trailer;
              return  trailer;
            }
            }
        }
        }
 
 
      /* Must be a name */
      /* Must be a name */
      *index = or32_regnum_from_name (*group, arg[1].str);
      *index = or32_regnum_from_name (*group, arg[1].str);
 
 
      if (*index >= 0)
      if (*index >= 0)
        {
        {
          return trailer;
          return trailer;
        }
        }
 
 
      /* Couldn't find it - print out a rude message */
      /* Couldn't find it - print out a rude message */
      ui_out_message (uiout, 0, "Register name not recognized in group.\n");
      ui_out_message (uiout, 0, "Register name not recognized in group.\n");
      *group = -1;
      *group = -1;
      *index = -1;
      *index = -1;
      return  trailer;
      return  trailer;
 
 
    default:
    default:
      /* Anything else is an error */
      /* Anything else is an error */
      ui_out_message (uiout, 0, "Unable to parse arguments\n");
      ui_out_message (uiout, 0, "Unable to parse arguments\n");
      *group = -1;
      *group = -1;
      *index = -1;
      *index = -1;
      return  trailer;
      return  trailer;
    }
    }
}       /* or32_parse_spr_params() */
}       /* or32_parse_spr_params() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Read a special purpose register from the target
/*!Read a special purpose register from the target
 
 
   This has to be done using the target remote command "readspr"
   This has to be done using the target remote command "readspr"
 
 
   @param[in] regnum  The register to read
   @param[in] regnum  The register to read
 
 
   @return  The value read */
   @return  The value read */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static ULONGEST
static ULONGEST
or32_read_spr (unsigned int  regnum)
or32_read_spr (unsigned int  regnum)
{
{
  struct ui_file    *uibuf = mem_fileopen ();
  struct ui_file    *uibuf = mem_fileopen ();
  char               cmd[sizeof ("readspr ffff")];
  char               cmd[sizeof ("readspr ffff")];
  unsigned long int  data;
  unsigned long int  data;
  char              *res;
  char              *res;
  long int           len;
  long int           len;
 
 
  /* Create the command string and pass it to target remote command function */
  /* Create the command string and pass it to target remote command function */
  sprintf (cmd, "readspr %4x", regnum);
  sprintf (cmd, "readspr %4x", regnum);
  target_rcmd (cmd, uibuf);
  target_rcmd (cmd, uibuf);
 
 
  /* Get the output for the UI file as a string */
  /* Get the output for the UI file as a string */
  res = ui_file_xstrdup (uibuf, &len);
  res = ui_file_xstrdup (uibuf, &len);
  sscanf (res, "%lx", &data);
  sscanf (res, "%lx", &data);
 
 
  /* Tidy up */
  /* Tidy up */
  xfree (res);
  xfree (res);
  ui_file_delete (uibuf);
  ui_file_delete (uibuf);
 
 
  return  (ULONGEST)data;
  return  (ULONGEST)data;
 
 
}       /* or32_read_spr() */
}       /* or32_read_spr() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Write a special purpose register on the target
/*!Write a special purpose register on the target
 
 
   This has to be done using the target remote command "writespr"
   This has to be done using the target remote command "writespr"
 
 
   Since the SPRs may map to GPR's or the other GDB register (PPC, NPC, SR),
   Since the SPRs may map to GPR's or the other GDB register (PPC, NPC, SR),
   any register cache is flushed.
   any register cache is flushed.
 
 
   @param[in] regnum  The register to write
   @param[in] regnum  The register to write
   @param[in] data  The value to write */
   @param[in] data  The value to write */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or32_write_spr (unsigned int  regnum,
or32_write_spr (unsigned int  regnum,
                ULONGEST      data)
                ULONGEST      data)
{
{
  struct ui_file    *uibuf = mem_fileopen ();
  struct ui_file    *uibuf = mem_fileopen ();
  char               cmd[sizeof ("writespr ffff ffffffff")];
  char               cmd[sizeof ("writespr ffff ffffffff")];
  char              *res;
  char              *res;
  long int           len;
  long int           len;
 
 
  /* Create the command string and pass it to target remote command function */
  /* Create the command string and pass it to target remote command function */
  sprintf (cmd, "writespr %4x %8llx", regnum, (long long unsigned int)data);
  sprintf (cmd, "writespr %4x %8llx", regnum, (long long unsigned int)data);
  target_rcmd (cmd, uibuf);
  target_rcmd (cmd, uibuf);
 
 
  /* Flush the register cache */
  /* Flush the register cache */
  registers_changed ();
  registers_changed ();
 
 
  /* We ignore the result - Rcmd can put out its own error messages. Just
  /* We ignore the result - Rcmd can put out its own error messages. Just
     tidy up */
     tidy up */
  ui_file_delete (uibuf);
  ui_file_delete (uibuf);
 
 
}       /* or32_write_spr() */
}       /* or32_write_spr() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Show the value of a special purpose register or group
/*!Show the value of a special purpose register or group
 
 
   This is a custom extension to the GDB info command.
   This is a custom extension to the GDB info command.
 
 
   @param[in] args
   @param[in] args
   @param[in] from_tty  True (1) if GDB is running from a TTY, false (0)
   @param[in] from_tty  True (1) if GDB is running from a TTY, false (0)
   otherwise. */
   otherwise. */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or32_info_spr_command (char *args,
or32_info_spr_command (char *args,
                       int   from_tty)
                       int   from_tty)
{
{
  int  group;
  int  group;
  int  index;
  int  index;
 
 
  char  spr_name[32];
  char  spr_name[32];
 
 
  or32_parse_spr_params (args, &group, &index, 0);
  or32_parse_spr_params (args, &group, &index, 0);
 
 
  if (group < 0)
  if (group < 0)
    {
    {
      return;                   /* Couldn't parse the args */
      return;                   /* Couldn't parse the args */
    }
    }
 
 
  if (index >= 0)
  if (index >= 0)
    {
    {
      ULONGEST  value = or32_read_spr (OR32_SPR (group, index));
      ULONGEST  value = or32_read_spr (OR32_SPR (group, index));
 
 
      ui_out_field_fmt (uiout, NULL, "%s.%s = SPR%i_%i = %llu (0x%llx)\n",
      ui_out_field_fmt (uiout, NULL, "%s.%s = SPR%i_%i = %llu (0x%llx)\n",
                        or32_spr_group_name (group),
                        or32_spr_group_name (group),
                        or32_spr_register_name (group, index, spr_name), group,
                        or32_spr_register_name (group, index, spr_name), group,
                        index, (long long unsigned int)value, (long long unsigned int)value);
                        index, (long long unsigned int)value, (long long unsigned int)value);
    }
    }
  else
  else
    {
    {
      /* Print all valid registers in the group */
      /* Print all valid registers in the group */
      for (index = 0; index < OR32_SPG_SIZE; index++)
      for (index = 0; index < OR32_SPG_SIZE; index++)
        {
        {
          if (0 != strlen (or32_spr_register_name (group, index, spr_name)))
          if (0 != strlen (or32_spr_register_name (group, index, spr_name)))
            {
            {
              ULONGEST  value = or32_read_spr (OR32_SPR (group, index));
              ULONGEST  value = or32_read_spr (OR32_SPR (group, index));
 
 
              ui_out_field_fmt (uiout, NULL,
              ui_out_field_fmt (uiout, NULL,
                                "%s.%s = SPR%i_%i = %llu (0x%llx)\n",
                                "%s.%s = SPR%i_%i = %llu (0x%llx)\n",
                                or32_spr_group_name (group),
                                or32_spr_group_name (group),
                                or32_spr_register_name (group, index, spr_name),
                                or32_spr_register_name (group, index, spr_name),
                                group, index, (long long unsigned int)value, (long long unsigned int)value);
                                group, index, (long long unsigned int)value, (long long unsigned int)value);
            }
            }
        }
        }
    }
    }
}       /* or32_info_spr_command() */
}       /* or32_info_spr_command() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Set a special purpose register
/*!Set a special purpose register
 
 
   This is a custom command added to GDB.
   This is a custom command added to GDB.
 
 
   @param[in] args
   @param[in] args
   @param[in] from_tty  True (1) if GDB is running from a TTY, false (0)
   @param[in] from_tty  True (1) if GDB is running from a TTY, false (0)
   otherwise. */
   otherwise. */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or32_spr_command (char *args,
or32_spr_command (char *args,
                  int   from_tty)
                  int   from_tty)
{
{
  int   group;
  int   group;
  int   index;
  int   index;
  char *tmp_str;
  char *tmp_str;
  char *nargs = or32_parse_spr_params (args, &group, &index, 1);
  char *nargs = or32_parse_spr_params (args, &group, &index, 1);
 
 
  ULONGEST  old_val;
  ULONGEST  old_val;
  ULONGEST  new_val;
  ULONGEST  new_val;
 
 
  char  spr_name[32];
  char  spr_name[32];
 
 
  /* Do we have a valid register spec? */
  /* Do we have a valid register spec? */
  if (index < 0)
  if (index < 0)
    {
    {
      return;           /* Parser will have printed the error message */
      return;           /* Parser will have printed the error message */
    }
    }
 
 
  /* Do we have a value to set? */
  /* Do we have a value to set? */
 
 
  errno = 0;
  errno = 0;
  new_val = (ULONGEST)strtoul (nargs, &tmp_str, 0);
  new_val = (ULONGEST)strtoul (nargs, &tmp_str, 0);
 
 
  if((0 != errno) || ('\0' != *tmp_str))
  if((0 != errno) || ('\0' != *tmp_str))
    {
    {
      ui_out_message (uiout, 0, "Invalid value - register not changed\n");
      ui_out_message (uiout, 0, "Invalid value - register not changed\n");
      return;
      return;
    }
    }
 
 
  old_val = or32_read_spr (OR32_SPR (group, index));
  old_val = or32_read_spr (OR32_SPR (group, index));
 
 
  or32_write_spr (OR32_SPR (group, index) , new_val);
  or32_write_spr (OR32_SPR (group, index) , new_val);
 
 
  ui_out_field_fmt (uiout, NULL,
  ui_out_field_fmt (uiout, NULL,
                    "%s.%s (SPR%i_%i) set to %llu (0x%llx), "
                    "%s.%s (SPR%i_%i) set to %llu (0x%llx), "
                    "was: %llu (0x%llx)\n",
                    "was: %llu (0x%llx)\n",
                    or32_spr_group_name (group),
                    or32_spr_group_name (group),
                    or32_spr_register_name (group, index, spr_name) , group,
                    or32_spr_register_name (group, index, spr_name) , group,
                    index, (long long unsigned int)new_val, (long long unsigned int)new_val, (long long unsigned int)old_val, (long long unsigned int)old_val);
                    index, (long long unsigned int)new_val, (long long unsigned int)new_val, (long long unsigned int)old_val, (long long unsigned int)old_val);
 
 
}       /* or32_spr_command() */
}       /* or32_spr_command() */
 
 
 
 
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*!Main entry point for target architecture initialization
/*!Main entry point for target architecture initialization
 
 
   In this version initializes the architecture via
   In this version initializes the architecture via
   registers_gdbarch_init(). Add a command to set and show special purpose
   registers_gdbarch_init(). Add a command to set and show special purpose
   registers. */
   registers. */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
void
void
_initialize_or32_tdep (void)
_initialize_or32_tdep (void)
{
{
  /* Register this architecture. We should do this for or16 and or64 when
  /* Register this architecture. We should do this for or16 and or64 when
     they have their BFD defined. */
     they have their BFD defined. */
  gdbarch_register (bfd_arch_or32, or32_gdbarch_init, or32_dump_tdep);
  gdbarch_register (bfd_arch_or32, or32_gdbarch_init, or32_dump_tdep);
 
 
  /* Initialize the automata for the assembler */
  /* Initialize the automata for the assembler */
  build_automata();
  build_automata();
 
 
  /* Commands to show and set special purpose registers */
  /* Commands to show and set special purpose registers */
  add_info ("spr", or32_info_spr_command,
  add_info ("spr", or32_info_spr_command,
            "Show the value of a special purpose register");
            "Show the value of a special purpose register");
  add_com ("spr", class_support, or32_spr_command,
  add_com ("spr", class_support, or32_spr_command,
           "Set a special purpose register");
           "Set a special purpose register");
 
 
}       /* _initialize_or32_tdep() */
}       /* _initialize_or32_tdep() */
 
 

powered by: WebSVN 2.1.0

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