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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-6.8/] [gdb/] [remote-or1k.c] - Diff between revs 827 and 840

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

Rev 827 Rev 840
/* Remote debugging interface for various or1k debugging protocols.
/* Remote debugging interface for various or1k debugging protocols.
   Currently supported or1k targets are: simulator, jtag, dummy.
   Currently supported or1k targets are: simulator, jtag, dummy.
 
 
   Copyright 1993-1995, 2000 Free Software Foundation, Inc.
   Copyright 1993-1995, 2000 Free Software Foundation, Inc.
   Copyright 2008 Embecosm Limited
   Copyright 2008 Embecosm Limited
 
 
   Contributed by Cygnus Support.  Written by Marko Mlinar
   Contributed by Cygnus Support.  Written by Marko Mlinar
   <markom@opencores.org>
   <markom@opencores.org>
   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/>.
*/
*/
 
 
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*!Updated for GDB 6.8 by Jeremy Bennett. All code converted to ANSI C style
/*!Updated for GDB 6.8 by Jeremy Bennett. All code converted to ANSI C style
   and in general to GDB format. All global OpenRISC specific functions and
   and in general to GDB format. All global OpenRISC specific functions and
   variables should now have a prefix of or1k_ or OR1K_.
   variables should now have a prefix of or1k_ or OR1K_.
 
 
   This original code defined three possible remote targets "jtag", "sim" and
   This original code defined three possible remote targets "jtag", "sim" and
   "dummy", all using the OpenRISC 1000 remote protocol. However only "jtag"
   "dummy", all using the OpenRISC 1000 remote protocol. However only "jtag"
   is actually implemented, and in this version, all the redundant code is
   is actually implemented, and in this version, all the redundant code is
   stripped out. The intention is that in time all remote debugging will be
   stripped out. The intention is that in time all remote debugging will be
   via the Remote Serial Protocol.
   via the Remote Serial Protocol.
 
 
   Commenting compatible with Doxygen added throughout. */
   Commenting compatible with Doxygen added throughout. */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
 
 
#include "defs.h"
#include "defs.h"
#include "inferior.h"
#include "inferior.h"
#include "bfd.h"
#include "bfd.h"
#include "symfile.h"
#include "symfile.h"
#include "gdb_wait.h"
#include "gdb_wait.h"
#include "gdbcmd.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "gdbcore.h"
#include "target.h"
#include "target.h"
#include "gdb_string.h"
#include "gdb_string.h"
#include "event-loop.h"
#include "event-loop.h"
#include "event-top.h"
#include "event-top.h"
#include "inf-loop.h"
#include "inf-loop.h"
#include "regcache.h"
#include "regcache.h"
 
 
#include <signal.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <fcntl.h>
 
 
#include "or1k-tdep.h"
#include "or1k-tdep.h"
#include "or1k-jtag.h"
#include "or1k-jtag.h"
#include "exceptions.h"
#include "exceptions.h"
#include "frame.h"
#include "frame.h"
#include "opcode/or32.h"
#include "opcode/or32.h"
#include "solib.h"
#include "solib.h"
 
 
#include <arpa/inet.h>
#include <arpa/inet.h>
 
 
 
 
/*! The current OR1K target */
/*! The current OR1K target */
static struct target_ops  or1k_target;
static struct target_ops  or1k_target;
 
 
/*! Are we single stepping */
/*! Are we single stepping */
static int  or1k_is_single_stepping;
static int  or1k_is_single_stepping;
 
 
/*! Cached OR1K debug register values (ignores counters for now). */
/*! Cached OR1K debug register values (ignores counters for now). */
static struct {
static struct {
  unsigned long int  dvr[OR1K_MAX_MATCHPOINTS];
  unsigned long int  dvr[OR1K_MAX_MATCHPOINTS];
  struct {
  struct {
    enum {
    enum {
      OR1K_CT_DISABLED = 0,              /* Disabled */
      OR1K_CT_DISABLED = 0,              /* Disabled */
      OR1K_CT_FETCH    = 1,             /* Compare to fetch EA */
      OR1K_CT_FETCH    = 1,             /* Compare to fetch EA */
      OR1K_CT_LEA      = 2,             /* Compare to load EA */
      OR1K_CT_LEA      = 2,             /* Compare to load EA */
      OR1K_CT_SEA      = 3,             /* Compare to store EA */
      OR1K_CT_SEA      = 3,             /* Compare to store EA */
      OR1K_CT_LDATA    = 4,             /* Compare to load data */
      OR1K_CT_LDATA    = 4,             /* Compare to load data */
      OR1K_CT_SDATA    = 5,             /* Compare to store data */
      OR1K_CT_SDATA    = 5,             /* Compare to store data */
      OR1K_CT_AEA      = 6,             /* Compare to load/store EA */
      OR1K_CT_AEA      = 6,             /* Compare to load/store EA */
      OR1K_CT_ADATA    = 7              /* Compare to load/store data */
      OR1K_CT_ADATA    = 7              /* Compare to load/store data */
    }    ct;                            /* Compare to what? */
    }    ct;                            /* Compare to what? */
    int  sc;                            /* Signed comparision */
    int  sc;                            /* Signed comparision */
    enum {
    enum {
      OR1K_CC_MASKED   = 0,
      OR1K_CC_MASKED   = 0,
      OR1K_CC_EQ       = 1,
      OR1K_CC_EQ       = 1,
      OR1K_CC_LT       = 2,
      OR1K_CC_LT       = 2,
      OR1K_CC_LE       = 3,
      OR1K_CC_LE       = 3,
      OR1K_CC_GT       = 4,
      OR1K_CC_GT       = 4,
      OR1K_CC_GE       = 5,
      OR1K_CC_GE       = 5,
      OR1K_CC_NE       = 6,
      OR1K_CC_NE       = 6,
      OR1K_CC_RESERVED = 7
      OR1K_CC_RESERVED = 7
    }    cc;                            /* Compare operation */
    }    cc;                            /* Compare operation */
    int  dp;                            /* DVR/DCP present */
    int  dp;                            /* DVR/DCP present */
  }                  dcr[OR1K_MAX_MATCHPOINTS];
  }                  dcr[OR1K_MAX_MATCHPOINTS];
  unsigned long int  dmr1;
  unsigned long int  dmr1;
  unsigned long int  dmr2;
  unsigned long int  dmr2;
  unsigned long int  dsr;
  unsigned long int  dsr;
  unsigned long int  drr;
  unsigned long int  drr;
} or1k_dbgcache;
} or1k_dbgcache;
 
 
/*! Old SIGINT handler.  */
/*! Old SIGINT handler.  */
static void (*or1k_old_intr_handler) (int) = NULL;
static void (*or1k_old_intr_handler) (int) = NULL;
 
 
/* Forward declaration of global functions to access SPRs. */
/* Forward declaration of global functions to access SPRs. */
 
 
ULONGEST  or1k_read_spr (unsigned int  regnum);
ULONGEST  or1k_read_spr (unsigned int  regnum);
void      or1k_write_spr (unsigned int  regnum,
void      or1k_write_spr (unsigned int  regnum,
                          ULONGEST      data);
                          ULONGEST      data);
 
 
/* Forward declaration of support functions to handle user interrupt */
/* Forward declaration of support functions to handle user interrupt */
 
 
static void  or1k_interrupt_query();
static void  or1k_interrupt_query();
static void  or1k_interrupt (int signo);
static void  or1k_interrupt (int signo);
static void  or1k_interrupt_twice (int signo);
static void  or1k_interrupt_twice (int signo);
 
 
/* Forward declaration of support functions to handle breakpoints */
/* Forward declaration of support functions to handle breakpoints */
 
 
static unsigned char  or1k_gdb_to_dcr_type (enum target_hw_bp_type  gdb_type);
static unsigned char  or1k_gdb_to_dcr_type (enum target_hw_bp_type  gdb_type);
static int            or1k_set_breakpoint (CORE_ADDR  addr);
static int            or1k_set_breakpoint (CORE_ADDR  addr);
static int            or1k_clear_breakpoint (CORE_ADDR  addr);
static int            or1k_clear_breakpoint (CORE_ADDR  addr);
static int            or1k_watchpoint_gc ();
static int            or1k_watchpoint_gc ();
static int            or1k_stopped_watchpoint_info (CORE_ADDR *addr_p,
static int            or1k_stopped_watchpoint_info (CORE_ADDR *addr_p,
                                                    int       *mp_p);
                                                    int       *mp_p);
 
 
/* Forward declarations of support functions for the remote operations */
/* Forward declarations of support functions for the remote operations */
 
 
static int        or1k_regnum_to_sprnum (int regnum);
static int        or1k_regnum_to_sprnum (int regnum);
static void       or1k_commit_debug_registers();
static void       or1k_commit_debug_registers();
static void       or1k_start_remote (struct ui_out *uiout,
static void       or1k_start_remote (struct ui_out *uiout,
                                     void          *arg);
                                     void          *arg);
 
 
/* Forward declarations of functions for the remote operations */
/* Forward declarations of functions for the remote operations */
 
 
static void     or1k_files_info (struct target_ops *target);
static void     or1k_files_info (struct target_ops *target);
static void     or1k_open (char *name,
static void     or1k_open (char *name,
                           int   from_tty);
                           int   from_tty);
static void     or1k_close (int quitting);
static void     or1k_close (int quitting);
static void     or1k_detach (char *args,
static void     or1k_detach (char *args,
                             int   from_tty);
                             int   from_tty);
static void     or1k_fetch_registers (struct regcache *regcache,
static void     or1k_fetch_registers (struct regcache *regcache,
                                      int              regnum);
                                      int              regnum);
static void     or1k_store_registers (struct regcache *regcache,
static void     or1k_store_registers (struct regcache *regcache,
                                      int              regnum);
                                      int              regnum);
static void     or1k_prepare_to_store (struct regcache *regcache);
static void     or1k_prepare_to_store (struct regcache *regcache);
static LONGEST  or1k_xfer_partial (struct target_ops  *ops,
static LONGEST  or1k_xfer_partial (struct target_ops  *ops,
                                   enum target_object  object,
                                   enum target_object  object,
                                   const char         *annex,
                                   const char         *annex,
                                   gdb_byte           *readbuf,
                                   gdb_byte           *readbuf,
                                   const gdb_byte     *writebuf,
                                   const gdb_byte     *writebuf,
                                   ULONGEST            offset,
                                   ULONGEST            offset,
                                   LONGEST             len);
                                   LONGEST             len);
static int      or1k_insert_breakpoint (struct bp_target_info *bpi);
static int      or1k_insert_breakpoint (struct bp_target_info *bpi);
static int      or1k_remove_breakpoint (struct bp_target_info *bpi);
static int      or1k_remove_breakpoint (struct bp_target_info *bpi);
static int      or1k_can_use_hw_matchpoint (int  type,
static int      or1k_can_use_hw_matchpoint (int  type,
                                            int  count,
                                            int  count,
                                            int  othertype);
                                            int  othertype);
static int      or1k_insert_hw_breakpoint (struct bp_target_info *bpi);
static int      or1k_insert_hw_breakpoint (struct bp_target_info *bpi);
static int      or1k_remove_hw_breakpoint (struct bp_target_info *bpi);
static int      or1k_remove_hw_breakpoint (struct bp_target_info *bpi);
static int      or1k_insert_watchpoint (CORE_ADDR  addr,
static int      or1k_insert_watchpoint (CORE_ADDR  addr,
                                        int        len,
                                        int        len,
                                        int        type);
                                        int        type);
static int      or1k_remove_watchpoint (CORE_ADDR  addr,
static int      or1k_remove_watchpoint (CORE_ADDR  addr,
                                        int        len,
                                        int        len,
                                        int        type);
                                        int        type);
static int      or1k_stopped_by_watchpoint();
static int      or1k_stopped_by_watchpoint();
static int      or1k_stopped_data_address (struct target_ops *target,
static int      or1k_stopped_data_address (struct target_ops *target,
                                           CORE_ADDR         *addr_p);
                                           CORE_ADDR         *addr_p);
static int      or1k_region_ok_for_hw_watchpoint (CORE_ADDR  addr,
static int      or1k_region_ok_for_hw_watchpoint (CORE_ADDR  addr,
                                                  int        len);
                                                  int        len);
static void     or1k_resume (ptid_t              ptid,
static void     or1k_resume (ptid_t              ptid,
                             int                 step,
                             int                 step,
                             enum target_signal  sig);
                             enum target_signal  sig);
static ptid_t   or1k_wait (ptid_t                    remote_ptid,
static ptid_t   or1k_wait (ptid_t                    remote_ptid,
                           struct target_waitstatus *status);
                           struct target_waitstatus *status);
static void     or1k_stop ();
static void     or1k_stop ();
static void     or1k_kill ();
static void     or1k_kill ();
static void     or1k_create_inferior (char  *execfile,
static void     or1k_create_inferior (char  *execfile,
                                      char  *args,
                                      char  *args,
                                      char **env,
                                      char **env,
                                      int    from_tty);
                                      int    from_tty);
static void     or1k_mourn_inferior ();
static void     or1k_mourn_inferior ();
static void     or1k_rcmd (char           *command,
static void     or1k_rcmd (char           *command,
                           struct ui_file *outbuf);
                           struct ui_file *outbuf);
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Ask the user about an interrupt
/*!Ask the user about an interrupt
 
 
  Ctrl-C has been received. */
  Ctrl-C has been received. */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_interrupt_query()
or1k_interrupt_query()
{
{
  target_terminal_ours ();
  target_terminal_ours ();
 
 
  if (query ("OpenRISC remote JTAG interrupted while waiting for the program\n"
  if (query ("OpenRISC remote JTAG interrupted while waiting for the program\n"
             "Give up (and stop debugging it)? "))
             "Give up (and stop debugging it)? "))
    {
    {
      const struct gdb_exception e = {
      const struct gdb_exception e = {
        .reason  = RETURN_QUIT,
        .reason  = RETURN_QUIT,
        .error   = GENERIC_ERROR,
        .error   = GENERIC_ERROR,
        .message = "OpenRISC remote JTAG debugging interrupted"
        .message = "OpenRISC remote JTAG debugging interrupted"
      };
      };
 
 
      or1k_mourn_inferior ();
      or1k_mourn_inferior ();
      throw_exception (e);
      throw_exception (e);
    }
    }
 
 
  target_terminal_inferior ();
  target_terminal_inferior ();
 
 
}       /* or1k_interrupt_query() */
}       /* or1k_interrupt_query() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!The command line interface's stop routine from an interrupt
/*!The command line interface's stop routine from an interrupt
 
 
   Attempt to stop the processor. Set a more severe interrupt routine, so that
   Attempt to stop the processor. Set a more severe interrupt routine, so that
   a second ctrl-C will force more aggressive behavior.
   a second ctrl-C will force more aggressive behavior.
 
 
   @param[in] signo  The signal which triggered this handle (always SIGINT) */
   @param[in] signo  The signal which triggered this handle (always SIGINT) */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_interrupt (int signo)
or1k_interrupt (int signo)
{
{
  quit_flag = 1;                /* For passive stops */
  quit_flag = 1;                /* For passive stops */
  or1k_stop ();                 /* Actively stall the processor */
  or1k_stop ();                 /* Actively stall the processor */
 
 
  /* If this doesn't work, try more severe steps. */
  /* If this doesn't work, try more severe steps. */
  signal (signo, or1k_interrupt_twice);
  signal (signo, or1k_interrupt_twice);
 
 
}       /* or1k_interrupt() */
}       /* or1k_interrupt() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!More aggressive interrupt handler
/*!More aggressive interrupt handler
 
 
   The user typed ^C twice. We ask if they want to kill everything. If they
   The user typed ^C twice. We ask if they want to kill everything. If they
   don't we put this signal handler back in place, so another ctrl-C will
   don't we put this signal handler back in place, so another ctrl-C will
   bring us back heer.
   bring us back heer.
 
 
   @param[in] signo  The signal which triggered this handle (always SIGINT) */
   @param[in] signo  The signal which triggered this handle (always SIGINT) */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_interrupt_twice (int signo)
or1k_interrupt_twice (int signo)
{
{
  /* Restore the old interrupt handler */
  /* Restore the old interrupt handler */
  if (NULL != or1k_old_intr_handler)
  if (NULL != or1k_old_intr_handler)
    {
    {
      signal (signo, or1k_old_intr_handler);
      signal (signo, or1k_old_intr_handler);
    }
    }
 
 
  or1k_interrupt_query();
  or1k_interrupt_query();
 
 
  /* If we carry on keep this as the signal handler */
  /* If we carry on keep this as the signal handler */
  signal (signo, or1k_interrupt_twice);
  signal (signo, or1k_interrupt_twice);
 
 
}       /* or1k_interrupt_twice() */
}       /* or1k_interrupt_twice() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Translate GDB watchpoint type into data control register compare to bits
/*!Translate GDB watchpoint type into data control register compare to bits
 
 
   @param[in] gdb_type  GDB watchpoint type
   @param[in] gdb_type  GDB watchpoint type
 
 
   @return  The corresponding data control register compare to bits */
   @return  The corresponding data control register compare to bits */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static unsigned char
static unsigned char
or1k_gdb_to_dcr_type (enum target_hw_bp_type  gdb_type)
or1k_gdb_to_dcr_type (enum target_hw_bp_type  gdb_type)
{
{
  switch (gdb_type)
  switch (gdb_type)
    {
    {
    case hw_write:  return  OR1K_CT_SEA;
    case hw_write:  return  OR1K_CT_SEA;
    case hw_read:   return  OR1K_CT_LEA;
    case hw_read:   return  OR1K_CT_LEA;
    case hw_access: return  OR1K_CT_AEA;
    case hw_access: return  OR1K_CT_AEA;
 
 
    default:
    default:
      error  ("or1k_gdb_to_dcr_type: Invalid type %d\n", gdb_type );
      error  ("or1k_gdb_to_dcr_type: Invalid type %d\n", gdb_type );
      return  -1;
      return  -1;
    }
    }
}       /* or1k_gdb_to_dcr_type */
}       /* or1k_gdb_to_dcr_type */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Find the first free matchpoint
/*!Find the first free matchpoint
 
 
  @return  The first free matchpoint, or -1 if none is available. */
  @return  The first free matchpoint, or -1 if none is available. */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_first_free_matchpoint ()
or1k_first_free_matchpoint ()
{
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  int i;
  int i;
 
 
  /* Search for unused matchpoint.  */
  /* Search for unused matchpoint.  */
  for (i = 0; i < tdep->num_matchpoints; i++)
  for (i = 0; i < tdep->num_matchpoints; i++)
    {
    {
      if (!or1k_dbgcache.dcr[i].dp)
      if (!or1k_dbgcache.dcr[i].dp)
        {
        {
          return  i;
          return  i;
        }
        }
    }
    }
 
 
  return  -1;
  return  -1;
 
 
}       /* or1k_first_free_matchpoint() */
}       /* or1k_first_free_matchpoint() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set a breakpoint.
/*!Set a breakpoint.
 
 
   @param[in] addr  The address at which to set the breakpoint
   @param[in] addr  The address at which to set the breakpoint
 
 
   @return  0 if the breakpoint was set, non-zero otherwise */
   @return  0 if the breakpoint was set, non-zero otherwise */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_set_breakpoint (CORE_ADDR  addr)
or1k_set_breakpoint (CORE_ADDR  addr)
{
{
  int mp = or1k_first_free_matchpoint();
  int mp = or1k_first_free_matchpoint();
 
 
  if (mp < 0)
  if (mp < 0)
    {
    {
      return  1;
      return  1;
    }
    }
 
 
  /* Set the value register to the address where we should breakpoint and the
  /* Set the value register to the address where we should breakpoint and the
     control register for unsigned match to the fetched effective address. */
     control register for unsigned match to the fetched effective address. */
  or1k_dbgcache.dvr[mp]    = addr;
  or1k_dbgcache.dvr[mp]    = addr;
 
 
  or1k_dbgcache.dcr[mp].dp = 1;
  or1k_dbgcache.dcr[mp].dp = 1;
  or1k_dbgcache.dcr[mp].cc = OR1K_CC_EQ;
  or1k_dbgcache.dcr[mp].cc = OR1K_CC_EQ;
  or1k_dbgcache.dcr[mp].sc = 0;
  or1k_dbgcache.dcr[mp].sc = 0;
  or1k_dbgcache.dcr[mp].ct = OR1K_CT_FETCH;
  or1k_dbgcache.dcr[mp].ct = OR1K_CT_FETCH;
 
 
  /* No chaining here. Watchpoint triggers a break */
  /* No chaining here. Watchpoint triggers a break */
  or1k_dbgcache.dmr1 &= ~(OR1K_DMR1_CW << (OR1K_DMR1_CW_SZ * mp));
  or1k_dbgcache.dmr1 &= ~(OR1K_DMR1_CW << (OR1K_DMR1_CW_SZ * mp));
  or1k_dbgcache.dmr2 |= (1 << (mp + OR1K_DMR2_WGB_OFF));
  or1k_dbgcache.dmr2 |= (1 << (mp + OR1K_DMR2_WGB_OFF));
 
 
  return 0;
  return 0;
 
 
}       /* or1k_set_breakpoint() */
}       /* or1k_set_breakpoint() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!See if a matchpoint has the given qualities
/*!See if a matchpoint has the given qualities
 
 
   The fields in the matchpoint DVR and DCR registers must match and the
   The fields in the matchpoint DVR and DCR registers must match and the
   matchpoint must be in use.
   matchpoint must be in use.
 
 
   @param[in] mp    The matchpoint of interest
   @param[in] mp    The matchpoint of interest
   @param[in] addr  The address to compare
   @param[in] addr  The address to compare
   @param[in] cc    The condition code to compare
   @param[in] cc    The condition code to compare
   @param[in] sc    The signedness to compare
   @param[in] sc    The signedness to compare
   @param[in] ct    The comparision type to compare
   @param[in] ct    The comparision type to compare
 
 
   @return  1 (true) if the fields are the same and the matchpoint is in use */
   @return  1 (true) if the fields are the same and the matchpoint is in use */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_matchpoint_equal (int            mp,
or1k_matchpoint_equal (int            mp,
                       CORE_ADDR      addr,
                       CORE_ADDR      addr,
                       unsigned char  cc,
                       unsigned char  cc,
                       unsigned char  sc,
                       unsigned char  sc,
                       unsigned char  ct)
                       unsigned char  ct)
{
{
  int res =  or1k_dbgcache.dcr[mp].dp          &&
  int res =  or1k_dbgcache.dcr[mp].dp          &&
            (or1k_dbgcache.dcr[mp].cc == cc  ) &&
            (or1k_dbgcache.dcr[mp].cc == cc  ) &&
            (or1k_dbgcache.dcr[mp].sc == sc  ) &&
            (or1k_dbgcache.dcr[mp].sc == sc  ) &&
            (or1k_dbgcache.dcr[mp].ct == ct  ) &&
            (or1k_dbgcache.dcr[mp].ct == ct  ) &&
            (or1k_dbgcache.dvr[mp]    == addr);
            (or1k_dbgcache.dvr[mp]    == addr);
 
 
  return  res;
  return  res;
 
 
}       /* or1k_matchpoint_equal() */
}       /* or1k_matchpoint_equal() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Clear a breakpoint.
/*!Clear a breakpoint.
 
 
   @param[in] addr  The address at which to clear the breakpoint
   @param[in] addr  The address at which to clear the breakpoint
 
 
   @return  0 if the breakpoint was cleared, non-zero otherwise */
   @return  0 if the breakpoint was cleared, non-zero otherwise */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_clear_breakpoint (CORE_ADDR  addr)
or1k_clear_breakpoint (CORE_ADDR  addr)
{
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  int                  mp;
  int                  mp;
 
 
  /* Search for matching breakpoint.  */
  /* Search for matching breakpoint.  */
  for (mp = 0; mp < tdep->num_matchpoints; mp++)
  for (mp = 0; mp < tdep->num_matchpoints; mp++)
    {
    {
      if (or1k_matchpoint_equal (mp, addr, OR1K_CC_EQ, 0, OR1K_CT_FETCH))
      if (or1k_matchpoint_equal (mp, addr, OR1K_CC_EQ, 0, OR1K_CT_FETCH))
        {
        {
          break;
          break;
        }
        }
    }
    }
 
 
  if (mp >= tdep->num_matchpoints)
  if (mp >= tdep->num_matchpoints)
    {
    {
      return 1;
      return 1;
    }
    }
 
 
  /* Mark the matchpoint unused and clear its bits in the assign to counter,
  /* Mark the matchpoint unused and clear its bits in the assign to counter,
     watchpoint generating break and breakpoint status bits in DMR2. */
     watchpoint generating break and breakpoint status bits in DMR2. */
  or1k_dbgcache.dcr[mp].dp = 0;
  or1k_dbgcache.dcr[mp].dp = 0;
 
 
  or1k_dbgcache.dmr2 &= ~(1 << (mp + OR1K_DMR2_AWTC_OFF));
  or1k_dbgcache.dmr2 &= ~(1 << (mp + OR1K_DMR2_AWTC_OFF));
  or1k_dbgcache.dmr2 &= ~(1 << (mp + OR1K_DMR2_WGB_OFF));
  or1k_dbgcache.dmr2 &= ~(1 << (mp + OR1K_DMR2_WGB_OFF));
  or1k_dbgcache.dmr2 &= ~(1 << (mp + OR1K_DMR2_WBS_OFF));
  or1k_dbgcache.dmr2 &= ~(1 << (mp + OR1K_DMR2_WBS_OFF));
 
 
  return 0;
  return 0;
 
 
}       /* or1k_clear_breakpoint() */
}       /* or1k_clear_breakpoint() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Garbage collect the HW watchpoints
/*!Garbage collect the HW watchpoints
 
 
   Some functions require more than one OpenRISC 1000 HW watchpoint to be
   Some functions require more than one OpenRISC 1000 HW watchpoint to be
   chained together. Chained wathcpoints must be adjacent, but setting of
   chained together. Chained wathcpoints must be adjacent, but setting of
   breakpoints (which uses a single HW matchpoint/watchpoint) can lead to
   breakpoints (which uses a single HW matchpoint/watchpoint) can lead to
   fragmentation of the watchpoint list.
   fragmentation of the watchpoint list.
 
 
   This function allows the currently used matchpoints to be shuffled up. In
   This function allows the currently used matchpoints to be shuffled up. In
   other words we have a GARBAGE COLLECTOR (omninous music, thunder
   other words we have a GARBAGE COLLECTOR (omninous music, thunder
   clouds gather, lightning flashes).
   clouds gather, lightning flashes).
 
 
   For added fun, watchpoints 8 and 9 cannot be moved, and hence nothing that
   For added fun, watchpoints 8 and 9 cannot be moved, and hence nothing that
   depends on them.
   depends on them.
 
 
   @return  The number of free watchpoints */
   @return  The number of free watchpoints */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_watchpoint_gc ()
or1k_watchpoint_gc ()
{
{
  struct gdbarch_tdep *tdep          = gdbarch_tdep (current_gdbarch);
  struct gdbarch_tdep *tdep          = gdbarch_tdep (current_gdbarch);
  unsigned long int    bits;
  unsigned long int    bits;
  int                  first_free;
  int                  first_free;
  int                  first_used;
  int                  first_used;
  int                  first_fixed;
  int                  first_fixed;
 
 
  /* Find the last moveable watchpoint by starting from the top and working
  /* Find the last moveable watchpoint by starting from the top and working
     down until we find a point where the watchpoint is not dependent on its
     down until we find a point where the watchpoint is not dependent on its
     predecessor. */
     predecessor. */
 
 
  for (first_fixed = tdep->num_matchpoints; first_fixed > 0; first_fixed--)
  for (first_fixed = tdep->num_matchpoints; first_fixed > 0; first_fixed--)
    {
    {
      bits = (or1k_dbgcache.dmr1 >> (OR1K_DMR1_CW_SZ * first_fixed)) &
      bits = (or1k_dbgcache.dmr1 >> (OR1K_DMR1_CW_SZ * first_fixed)) &
             OR1K_DMR1_CW;
             OR1K_DMR1_CW;
 
 
      if ((OR1K_DMR1_CW_AND != bits) && (OR1K_DMR1_CW_OR != bits))
      if ((OR1K_DMR1_CW_AND != bits) && (OR1K_DMR1_CW_OR != bits))
        {
        {
          break;                /* Chain is broken */
          break;                /* Chain is broken */
        }
        }
    }
    }
 
 
  /* Give up if there aren't two to be considered */
  /* Give up if there aren't two to be considered */
  if (first_fixed < 2)
  if (first_fixed < 2)
    {
    {
      return  first_fixed;
      return  first_fixed;
    }
    }
 
 
  /* Move matchpoints, and hence unused HW watchpoints to the top (i.e to
  /* Move matchpoints, and hence unused HW watchpoints to the top (i.e to
     first_fixed - 1). If we move a matchpoint, then all the HW watchpoints
     first_fixed - 1). If we move a matchpoint, then all the HW watchpoints
     above must be shuffled down. Although HW watchpoints refer to
     above must be shuffled down. Although HW watchpoints refer to
     matchpoints, it is a fixed reference based on index. So long as the HW
     matchpoints, it is a fixed reference based on index. So long as the HW
     watchpoint and the matchpoint are moved together, and the ordering
     watchpoint and the matchpoint are moved together, and the ordering
     remains unchanged all will be OK. Any chained watchpoints will be
     remains unchanged all will be OK. Any chained watchpoints will be
     adjacent, and will remain adjacent after this exercise. */
     adjacent, and will remain adjacent after this exercise. */
 
 
  first_free = 0;
  first_free = 0;
  first_used = 0;
  first_used = 0;
 
 
  while (1)
  while (1)
    {
    {
      /* Find the first free matchpoint */
      /* Find the first free matchpoint */
      for( ; first_free < first_fixed; first_free++ )
      for( ; first_free < first_fixed; first_free++ )
        {
        {
          if (!(or1k_dbgcache.dcr[first_free].dp))
          if (!(or1k_dbgcache.dcr[first_free].dp))
            {
            {
              break;
              break;
            }
            }
        }
        }
 
 
      if (first_free > (first_fixed - 2))
      if (first_free > (first_fixed - 2))
        {
        {
          return first_fixed - first_free;      /* No more to move */
          return first_fixed - first_free;      /* No more to move */
        }
        }
 
 
      /* Find the first fixed breakpoint */
      /* Find the first fixed breakpoint */
      for (first_used = first_free + 1; first_used < first_fixed; first_used++)
      for (first_used = first_free + 1; first_used < first_fixed; first_used++)
        {
        {
          if (or1k_dbgcache.dcr[first_used].dp)
          if (or1k_dbgcache.dcr[first_used].dp)
            {
            {
              break;
              break;
            }
            }
        }
        }
 
 
      if (first_used >  (first_fixed - 1))
      if (first_used >  (first_fixed - 1))
        {
        {
          return first_fixed - first_free;      /* No more to move */
          return first_fixed - first_free;      /* No more to move */
        }
        }
 
 
      /* Move matchpoint in DVR and DCR registers. */
      /* Move matchpoint in DVR and DCR registers. */
      or1k_dbgcache.dvr[first_free]    = or1k_dbgcache.dvr[first_used];
      or1k_dbgcache.dvr[first_free]    = or1k_dbgcache.dvr[first_used];
      or1k_dbgcache.dcr[first_free]    = or1k_dbgcache.dcr[first_used];
      or1k_dbgcache.dcr[first_free]    = or1k_dbgcache.dcr[first_used];
      or1k_dbgcache.dcr[first_used].dp = 0;
      or1k_dbgcache.dcr[first_used].dp = 0;
 
 
      /* Copy chaining bits in DMR1.  */
      /* Copy chaining bits in DMR1.  */
      bits = (or1k_dbgcache.dmr1 >> (OR1K_DMR1_CW_SZ * first_used)) &
      bits = (or1k_dbgcache.dmr1 >> (OR1K_DMR1_CW_SZ * first_used)) &
             OR1K_DMR1_CW;
             OR1K_DMR1_CW;
      or1k_dbgcache.dmr1 &= ~(OR1K_DMR1_CW << (OR1K_DMR1_CW_SZ * first_used));
      or1k_dbgcache.dmr1 &= ~(OR1K_DMR1_CW << (OR1K_DMR1_CW_SZ * first_used));
      or1k_dbgcache.dmr1 &= ~(OR1K_DMR1_CW << (OR1K_DMR1_CW_SZ * first_free));
      or1k_dbgcache.dmr1 &= ~(OR1K_DMR1_CW << (OR1K_DMR1_CW_SZ * first_free));
      or1k_dbgcache.dmr1 |=  (bits         << (OR1K_DMR1_CW_SZ * first_free));
      or1k_dbgcache.dmr1 |=  (bits         << (OR1K_DMR1_CW_SZ * first_free));
 
 
      /* Copy assign to counter, watchpoint generating break and breakpoint
      /* Copy assign to counter, watchpoint generating break and breakpoint
         status bits in DMR2 */
         status bits in DMR2 */
 
 
      bits = (or1k_dbgcache.dmr2 >> (OR1K_DMR2_AWTC_OFF + first_used)) & 1;
      bits = (or1k_dbgcache.dmr2 >> (OR1K_DMR2_AWTC_OFF + first_used)) & 1;
      or1k_dbgcache.dmr2 &= ~(1    << (OR1K_DMR2_AWTC_OFF + first_used));
      or1k_dbgcache.dmr2 &= ~(1    << (OR1K_DMR2_AWTC_OFF + first_used));
      or1k_dbgcache.dmr2 &= ~(1    << (OR1K_DMR2_AWTC_OFF + first_free));
      or1k_dbgcache.dmr2 &= ~(1    << (OR1K_DMR2_AWTC_OFF + first_free));
      or1k_dbgcache.dmr2 |=  (bits << (OR1K_DMR2_AWTC_OFF + first_free));
      or1k_dbgcache.dmr2 |=  (bits << (OR1K_DMR2_AWTC_OFF + first_free));
 
 
      bits = (or1k_dbgcache.dmr2 >> (OR1K_DMR2_WGB_OFF + first_used)) & 1;
      bits = (or1k_dbgcache.dmr2 >> (OR1K_DMR2_WGB_OFF + first_used)) & 1;
      or1k_dbgcache.dmr2 &= ~(1    << (OR1K_DMR2_WGB_OFF + first_used));
      or1k_dbgcache.dmr2 &= ~(1    << (OR1K_DMR2_WGB_OFF + first_used));
      or1k_dbgcache.dmr2 &= ~(1    << (OR1K_DMR2_WGB_OFF + first_free));
      or1k_dbgcache.dmr2 &= ~(1    << (OR1K_DMR2_WGB_OFF + first_free));
      or1k_dbgcache.dmr2 |=  (bits << (OR1K_DMR2_WGB_OFF + first_free));
      or1k_dbgcache.dmr2 |=  (bits << (OR1K_DMR2_WGB_OFF + first_free));
 
 
      bits = (or1k_dbgcache.dmr2 >> (OR1K_DMR2_WBS_OFF + first_used)) & 1;
      bits = (or1k_dbgcache.dmr2 >> (OR1K_DMR2_WBS_OFF + first_used)) & 1;
      or1k_dbgcache.dmr2 &= ~(1    << (OR1K_DMR2_WBS_OFF + first_used));
      or1k_dbgcache.dmr2 &= ~(1    << (OR1K_DMR2_WBS_OFF + first_used));
      or1k_dbgcache.dmr2 &= ~(1    << (OR1K_DMR2_WBS_OFF + first_free));
      or1k_dbgcache.dmr2 &= ~(1    << (OR1K_DMR2_WBS_OFF + first_free));
      or1k_dbgcache.dmr2 |=  (bits << (OR1K_DMR2_WBS_OFF + first_free));
      or1k_dbgcache.dmr2 |=  (bits << (OR1K_DMR2_WBS_OFF + first_free));
 
 
      first_free++;
      first_free++;
    }
    }
}       /* or1k_watchpoint_gc() */
}       /* or1k_watchpoint_gc() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Find if we were stopped by a watchpoint, and if so which address
/*!Find if we were stopped by a watchpoint, and if so which address
 
 
   This is true if a triggered breakpoint was ANDed with the previous
   This is true if a triggered breakpoint was ANDed with the previous
   watchpoint in the chain. If so, the previous matchpoint has the start
   watchpoint in the chain. If so, the previous matchpoint has the start
   address.
   address.
 
 
   This is an internal utility for use by or1k_stopped_watchpoint() and
   This is an internal utility for use by or1k_stopped_watchpoint() and
   or1k_stopped_data_address().
   or1k_stopped_data_address().
 
 
   @note This will only find the FIRST watchpoint triggered.
   @note This will only find the FIRST watchpoint triggered.
 
 
   @param[out] addr_p  Where to put the address associated with the
   @param[out] addr_p  Where to put the address associated with the
                       watchpoint if non-NULL
                       watchpoint if non-NULL
   @param[out] mp_p    Where to put the matchpoint which triggered the WP
   @param[out] mp_p    Where to put the matchpoint which triggered the WP
 
 
   @return  1 (true) if we get the address, 0 (false) otherwise */
   @return  1 (true) if we get the address, 0 (false) otherwise */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_stopped_watchpoint_info (CORE_ADDR *addr_p,
or1k_stopped_watchpoint_info (CORE_ADDR *addr_p,
                              int       *mp_p)
                              int       *mp_p)
{
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  int                  mp;
  int                  mp;
 
 
  /* Cannot be the first matchpoint (it has to AND with one previous) */
  /* Cannot be the first matchpoint (it has to AND with one previous) */
  for( mp = 1 ; mp < tdep->num_matchpoints ; mp++ )
  for( mp = 1 ; mp < tdep->num_matchpoints ; mp++ )
    {
    {
      if (((or1k_dbgcache.dmr2 >> (mp + OR1K_DMR2_WBS_OFF)) & 1) &&
      if (((or1k_dbgcache.dmr2 >> (mp + OR1K_DMR2_WBS_OFF)) & 1) &&
          (OR1K_DMR1_CW_AND ==
          (OR1K_DMR1_CW_AND ==
           ((or1k_dbgcache.dmr1 >> (mp * OR1K_DMR1_CW_SZ)) & OR1K_DMR1_CW)))
           ((or1k_dbgcache.dmr1 >> (mp * OR1K_DMR1_CW_SZ)) & OR1K_DMR1_CW)))
        {
        {
          if (NULL != addr_p)
          if (NULL != addr_p)
            {
            {
              *addr_p = or1k_dbgcache.dvr[mp - 1];
              *addr_p = or1k_dbgcache.dvr[mp - 1];
            }
            }
 
 
          if (NULL != mp_p)
          if (NULL != mp_p)
            {
            {
              *mp_p = mp;
              *mp_p = mp;
            }
            }
 
 
          return  1;
          return  1;
        }
        }
    }
    }
 
 
  return  0;
  return  0;
 
 
}       /* or1k_stopped_watchpoint_info() */
}       /* or1k_stopped_watchpoint_info() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Convert a register number to SPR number
/*!Convert a register number to SPR number
 
 
   OR1K debug unit has GPRs mapped to SPRs, which are not compact, so we are
   OR1K debug unit has GPRs mapped to SPRs, which are not compact, so we are
   mapping them for GDB.
   mapping them for GDB.
 
 
   Rewritten by CZ 12/09/01
   Rewritten by CZ 12/09/01
 
 
   @param[in] regnum  The register
   @param[in] regnum  The register
 
 
   @return  The corresponding SPR or -1 on failure */
   @return  The corresponding SPR or -1 on failure */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_regnum_to_sprnum (int regnum)
or1k_regnum_to_sprnum (int regnum)
{
{
  /* The GPRs map as a block */
  /* The GPRs map as a block */
  if (regnum < OR1K_MAX_GPR_REGS)
  if (regnum < OR1K_MAX_GPR_REGS)
    {
    {
      return  OR1K_SPR (OR1K_SPG_SYS, OR1K_SPG_SYS_GPR + regnum);
      return  OR1K_SPR (OR1K_SPG_SYS, OR1K_SPG_SYS_GPR + regnum);
    }
    }
 
 
  /* The "special" registers */
  /* The "special" registers */
  switch (regnum)
  switch (regnum)
    {
    {
    case OR1K_PPC_REGNUM: return  OR1K_NPC_SPRNUM;
    case OR1K_PPC_REGNUM: return  OR1K_NPC_SPRNUM;
    case OR1K_NPC_REGNUM: return  OR1K_NPC_SPRNUM;
    case OR1K_NPC_REGNUM: return  OR1K_NPC_SPRNUM;
    case OR1K_SR_REGNUM:  return  OR1K_SR_SPRNUM;
    case OR1K_SR_REGNUM:  return  OR1K_SR_SPRNUM;
 
 
    default:
    default:
      error ("or1k_regnum_to_sprnum: invalid register number!");
      error ("or1k_regnum_to_sprnum: invalid register number!");
      break;
      break;
    }
    }
 
 
  return -1;
  return -1;
 
 
}       /* or1k_regnum_to_sprnum() */
}       /* or1k_regnum_to_sprnum() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Sync debug registers
/*!Sync debug registers
 
 
   Synchronizes debug registers in memory with those on target. This used to
   Synchronizes debug registers in memory with those on target. This used to
   track if there was any change, but there always is with debuggers, so now
   track if there was any change, but there always is with debuggers, so now
   we just write them every time.
   we just write them every time.
 
 
   The old code did a lot of this via low-level manipulation of the JTAG
   The old code did a lot of this via low-level manipulation of the JTAG
   interface. For now it is replaced by straightward reading/writing of the
   interface. For now it is replaced by straightward reading/writing of the
   SPRs. */
   SPRs. */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_commit_debug_registers()
or1k_commit_debug_registers()
{
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  int                  i;
  int                  i;
 
 
  /* Matchpoints (breakpoints, watchpoints).  */
  /* Matchpoints (breakpoints, watchpoints).  */
  for (i = 0; i < tdep->num_matchpoints; i++)
  for (i = 0; i < tdep->num_matchpoints; i++)
    {
    {
      unsigned long int  dcr = 0;
      unsigned long int  dcr = 0;
 
 
      dcr |= or1k_dbgcache.dcr[i].dp ? OR1K_DCR_DP : 0;
      dcr |= or1k_dbgcache.dcr[i].dp ? OR1K_DCR_DP : 0;
      dcr |= (or1k_dbgcache.dcr[i].cc << OR1K_DCR_CC_OFF) & OR1K_DCR_CC;
      dcr |= (or1k_dbgcache.dcr[i].cc << OR1K_DCR_CC_OFF) & OR1K_DCR_CC;
      dcr |= or1k_dbgcache.dcr[i].sc ? OR1K_DCR_SC : 0;
      dcr |= or1k_dbgcache.dcr[i].sc ? OR1K_DCR_SC : 0;
      dcr |= (or1k_dbgcache.dcr[i].ct << OR1K_DCR_CT_OFF) & OR1K_DCR_CT;
      dcr |= (or1k_dbgcache.dcr[i].ct << OR1K_DCR_CT_OFF) & OR1K_DCR_CT;
 
 
      or1k_jtag_write_spr (OR1K_DVR0_SPRNUM + i, or1k_dbgcache.dvr[i]);
      or1k_jtag_write_spr (OR1K_DVR0_SPRNUM + i, or1k_dbgcache.dvr[i]);
      or1k_jtag_write_spr (OR1K_DCR0_SPRNUM + i, dcr);
      or1k_jtag_write_spr (OR1K_DCR0_SPRNUM + i, dcr);
    }
    }
 
 
  or1k_jtag_write_spr (OR1K_DMR1_SPRNUM, or1k_dbgcache.dmr1);
  or1k_jtag_write_spr (OR1K_DMR1_SPRNUM, or1k_dbgcache.dmr1);
  or1k_jtag_write_spr (OR1K_DMR2_SPRNUM, or1k_dbgcache.dmr2);
  or1k_jtag_write_spr (OR1K_DMR2_SPRNUM, or1k_dbgcache.dmr2);
  or1k_jtag_write_spr (OR1K_DSR_SPRNUM,  or1k_dbgcache.dsr);
  or1k_jtag_write_spr (OR1K_DSR_SPRNUM,  or1k_dbgcache.dsr);
  or1k_jtag_write_spr (OR1K_DRR_SPRNUM,  or1k_dbgcache.drr);
  or1k_jtag_write_spr (OR1K_DRR_SPRNUM,  or1k_dbgcache.drr);
 
 
}       /* or1k_commit_debug_registers() */
}       /* or1k_commit_debug_registers() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Start the remote target
/*!Start the remote target
 
 
   This is a wrapper for GDB's start_remote function, suitable for use with
   This is a wrapper for GDB's start_remote function, suitable for use with
   catch_exception.
   catch_exception.
 
 
   @param[in] uiout  UI handle - not used
   @param[in] uiout  UI handle - not used
   @param[in] arg_p  Reference to the generic argument supplied through
   @param[in] arg_p  Reference to the generic argument supplied through
                     catch_exception. In this case a pointer to the from_tty
                     catch_exception. In this case a pointer to the from_tty
                     parameter. */
                     parameter. */
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
 
 
static void
static void
or1k_start_remote (struct ui_out *uiout,
or1k_start_remote (struct ui_out *uiout,
                   void          *arg_p)
                   void          *arg_p)
{
{
  int  from_tty = *((int *)arg_p);
  int  from_tty = *((int *)arg_p);
 
 
  start_remote( from_tty );
  start_remote( from_tty );
 
 
}       /* or1k_start_remote() */
}       /* or1k_start_remote() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Print info on this target.
/*!Print info on this target.
 
 
  @param[in] target  GDB ops for the target - ignored. */
  @param[in] target  GDB ops for the target - ignored. */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_files_info (struct target_ops *target)
or1k_files_info (struct target_ops *target)
{
{
  const char *status_name[] =
  const char *status_name[] =
    {
    {
      "UNDEFINED",
      "UNDEFINED",
      "CONNECTING",
      "CONNECTING",
      "DISCONNECTING",
      "DISCONNECTING",
      "RUNNING",
      "RUNNING",
      "STOPPED"
      "STOPPED"
    };
    };
 
 
  char *file = "nothing";
  char *file = "nothing";
 
 
  if (exec_bfd)
  if (exec_bfd)
    {
    {
      file = bfd_get_filename (exec_bfd);
      file = bfd_get_filename (exec_bfd);
    }
    }
 
 
  printf_filtered ("File \"%s\"", file);
  printf_filtered ("File \"%s\"", file);
 
 
  if (exec_bfd)
  if (exec_bfd)
    {
    {
      printf_filtered ("attached to %s running program %s: ",
      printf_filtered ("attached to %s running program %s: ",
                       target_shortname, file);
                       target_shortname, file);
    }
    }
}       /* or1k_files_info() */
}       /* or1k_files_info() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Open a connection to the remote server
/*!Open a connection to the remote server
 
 
   Initialise the connection, then push the current target.
   Initialise the connection, then push the current target.
 
 
   @param[in] name      The arguments passed to the target command on GDB -
   @param[in] name      The arguments passed to the target command on GDB -
                        usually the address of the remote server
                        usually the address of the remote server
   @param[in] from_tty  1 (true) if the GDB session is being run from a
   @param[in] from_tty  1 (true) if the GDB session is being run from a
                        terminal and so can receive messages. 0 (false)
                        terminal and so can receive messages. 0 (false)
                        otherwise. */
                        otherwise. */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_open (char *name,
or1k_open (char *name,
           int   from_tty)
           int   from_tty)
{
{
  struct gdbarch_tdep *tdep     = gdbarch_tdep (current_gdbarch);
  struct gdbarch_tdep *tdep     = gdbarch_tdep (current_gdbarch);
  int                  i;
  int                  i;
  unsigned int         tmp;
  unsigned int         tmp;
  struct gdb_exception ex;
  struct gdb_exception ex;
 
 
  /* Check nothing's still running. This will call or1k_close if anything is,
  /* Check nothing's still running. This will call or1k_close if anything is,
     which will close the connection. Having done this, any remaining target
     which will close the connection. Having done this, any remaining target
     instances should be unpushed from the stack */
     instances should be unpushed from the stack */
  target_preopen (from_tty);
  target_preopen (from_tty);
  unpush_target (&or1k_target);
  unpush_target (&or1k_target);
 
 
  /* Initialize the connection to the remote target. */
  /* Initialize the connection to the remote target. */
  or1k_jtag_init (name);
  or1k_jtag_init (name);
 
 
  /* Make sure we have system and debug groups implemented. */
  /* Make sure we have system and debug groups implemented. */
  tmp = or1k_jtag_read_spr (OR1K_UPR_SPRNUM);
  tmp = or1k_jtag_read_spr (OR1K_UPR_SPRNUM);
  if (0 == (tmp & OR1K_SPR_UPR_UP))
  if (0 == (tmp & OR1K_SPR_UPR_UP))
    {
    {
      error ("or1k_open: system group missing");
      error ("or1k_open: system group missing");
    }
    }
  if (0 == (tmp & OR1K_SPR_UPR_DUP))
  if (0 == (tmp & OR1K_SPR_UPR_DUP))
    {
    {
      error ("or1k_open: debug group missing");
      error ("or1k_open: debug group missing");
    }
    }
 
 
  /* Determine number of gpr_regs (this is a bit simplified - the bit just
  /* Determine number of gpr_regs (this is a bit simplified - the bit just
     means "less than 32", but we assume that means 16) and the number of
     means "less than 32", but we assume that means 16) and the number of
     supported watchpoints. */
     supported watchpoints. */
  tmp                = or1k_jtag_read_spr (OR1K_CPUCFGR_SPRNUM);
  tmp                = or1k_jtag_read_spr (OR1K_CPUCFGR_SPRNUM);
  tdep->num_gpr_regs = (0 == (tmp & OR1K_SPR_CPUCFGR_CGF)) ? 32 : 16;
  tdep->num_gpr_regs = (0 == (tmp & OR1K_SPR_CPUCFGR_CGF)) ? 32 : 16;
 
 
  tmp                   = or1k_jtag_read_spr (OR1K_DCFGR_SPRNUM);
  tmp                   = or1k_jtag_read_spr (OR1K_DCFGR_SPRNUM);
  tdep->num_matchpoints = (tmp & OR1K_SPR_DCFGR_NDP) + 1;
  tdep->num_matchpoints = (tmp & OR1K_SPR_DCFGR_NDP) + 1;
 
 
  /* Stall the processor. A pause after stalling is appropriate for real
  /* Stall the processor. A pause after stalling is appropriate for real
     hardware. */
     hardware. */
  or1k_jtag_stall ();
  or1k_jtag_stall ();
  usleep (1000);
  usleep (1000);
 
 
  /* Initialize the debug register cache. The DSR is set to stop when
  /* Initialize the debug register cache. The DSR is set to stop when
     breakpoint occurs. The cache will be written out before unstalling the
     breakpoint occurs. The cache will be written out before unstalling the
     processor. */
     processor. */
  for (i = 0; i < tdep->num_matchpoints; i++)
  for (i = 0; i < tdep->num_matchpoints; i++)
    {
    {
      or1k_dbgcache.dvr[i] = 0;
      or1k_dbgcache.dvr[i] = 0;
      memset (&or1k_dbgcache.dcr[i], 0, sizeof (or1k_dbgcache.dcr[i]));
      memset (&or1k_dbgcache.dcr[i], 0, sizeof (or1k_dbgcache.dcr[i]));
    }
    }
 
 
  or1k_dbgcache.dmr1 = 0;
  or1k_dbgcache.dmr1 = 0;
  or1k_dbgcache.dmr2 = 0;
  or1k_dbgcache.dmr2 = 0;
  or1k_dbgcache.dsr  = OR1K_DSR_TE;
  or1k_dbgcache.dsr  = OR1K_DSR_TE;
  or1k_dbgcache.drr  = 0;
  or1k_dbgcache.drr  = 0;
 
 
  /* The remote target connection stalls the target, so all aspects of a
  /* The remote target connection stalls the target, so all aspects of a
     running connection are there, except it doesn't actually have
     running connection are there, except it doesn't actually have
     execution. So we call target_mark_running, but then immediately mark it
     execution. So we call target_mark_running, but then immediately mark it
     as not having execution */
     as not having execution */
  push_target (&or1k_target);
  push_target (&or1k_target);
  target_mark_running (&or1k_target);
  target_mark_running (&or1k_target);
  target_has_execution = 0;
  target_has_execution = 0;
 
 
  /* Get rid of any old shared library symbols. */
  /* Get rid of any old shared library symbols. */
  no_shared_libraries (NULL, 0);
  no_shared_libraries (NULL, 0);
 
 
  /* We don't have a concept of processs or threads, so we use the null PTID
  /* We don't have a concept of processs or threads, so we use the null PTID
     for the target. Set this here before the start_remote() code uses it. */
     for the target. Set this here before the start_remote() code uses it. */
  inferior_ptid = null_ptid;
  inferior_ptid = null_ptid;
 
 
  /* Start the remote target. Uses our own wrapper, so we can wrap it to
  /* Start the remote target. Uses our own wrapper, so we can wrap it to
     catch the exeception if it goes tits up. */
     catch the exeception if it goes tits up. */
  ex = catch_exception (uiout, or1k_start_remote, &from_tty, RETURN_MASK_ALL);
  ex = catch_exception (uiout, or1k_start_remote, &from_tty, RETURN_MASK_ALL);
  if (ex.reason < 0)
  if (ex.reason < 0)
    {
    {
      pop_target ();
      pop_target ();
      throw_exception (ex);
      throw_exception (ex);
    }
    }
 
 
}       /* or1k_open() */
}       /* or1k_open() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Close a connection to the remote server
/*!Close a connection to the remote server
 
 
   Use the target extra op is there is one. Don't mourn the inferior - it
   Use the target extra op is there is one. Don't mourn the inferior - it
   calls us, so we'll get a never ending loop!
   calls us, so we'll get a never ending loop!
 
 
   param[in] quitting  If true (1) GDB is going to shut down, so don't worry
   param[in] quitting  If true (1) GDB is going to shut down, so don't worry
   to wait for everything to complete. */
   to wait for everything to complete. */
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
 
 
static void
static void
or1k_close (int quitting)
or1k_close (int quitting)
{
{
  or1k_jtag_close ();
  or1k_jtag_close ();
 
 
}       /* or1k_close() */
}       /* or1k_close() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Detach from the remote server
/*!Detach from the remote server
 
 
   There is only one remote connection, so no argument should be given.
   There is only one remote connection, so no argument should be given.
 
 
   @param[in] args      Any args given to the detach command
   @param[in] args      Any args given to the detach command
   @param[in] from_tty  True (1) if this GDB session is run from a terminal,
   @param[in] from_tty  True (1) if this GDB session is run from a terminal,
   so messages can be output. */
   so messages can be output. */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_detach (char *args,
or1k_detach (char *args,
             int   from_tty)
             int   from_tty)
{
{
  if (args)
  if (args)
    {
    {
      error ("or1k_detach: \"detach\" takes no arg when remote debugging\n");
      error ("or1k_detach: \"detach\" takes no arg when remote debugging\n");
    }
    }
 
 
  or1k_close (1);
  or1k_close (1);
 
 
  if (from_tty)
  if (from_tty)
    {
    {
      printf_unfiltered ("Ending remote or1k debugging\n");
      printf_unfiltered ("Ending remote or1k debugging\n");
    }
    }
}       /* or1k_detach() */
}       /* or1k_detach() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Fetch remote registers
/*!Fetch remote registers
 
 
   The remote registers are fetched into the register cache
   The remote registers are fetched into the register cache
 
 
   @param[in] regcache  The register cache to use
   @param[in] regcache  The register cache to use
   @param[in] regnum    The desired register number, or -1 if all are wanted */
   @param[in] regnum    The desired register number, or -1 if all are wanted */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_fetch_registers (struct regcache *regcache,
or1k_fetch_registers (struct regcache *regcache,
                      int              regnum)
                      int              regnum)
{
{
  unsigned long int  val;
  unsigned long int  val;
  char               buf[sizeof (CORE_ADDR) ];
  char               buf[sizeof (CORE_ADDR) ];
 
 
  if (-1 == regnum)
  if (-1 == regnum)
    {
    {
      /* Get the lot */
      /* Get the lot */
      for (regnum = 0; regnum < OR1K_NUM_REGS; regnum++)
      for (regnum = 0; regnum < OR1K_NUM_REGS; regnum++)
        {
        {
          or1k_fetch_registers (regcache, regnum);
          or1k_fetch_registers (regcache, regnum);
        }
        }
      return;
      return;
    }
    }
 
 
  if (regnum >= OR1K_NUM_REGS)
  if (regnum >= OR1K_NUM_REGS)
    {
    {
      error ("or1k_fetch_registers: invalid register number");
      error ("or1k_fetch_registers: invalid register number");
    }
    }
 
 
  /* Convert to SPRNUM and read.  */
  /* Convert to SPRNUM and read.  */
  val = or1k_jtag_read_spr (or1k_regnum_to_sprnum (regnum));
  val = or1k_jtag_read_spr (or1k_regnum_to_sprnum (regnum));
 
 
  /* We got the number the register holds, but gdb expects to see a value in
  /* We got the number the register holds, but gdb expects to see a value in
     the target byte ordering.
     the target byte ordering.
 
 
     This is new for GDB 6.8. Not sure if I need get_thread_regcache() using
     This is new for GDB 6.8. Not sure if I need get_thread_regcache() using
     the ptid instead here. The old code used supply_register(), but that no
     the ptid instead here. The old code used supply_register(), but that no
     longer exists, so we hope regcache_raw_supply will do instead. */
     longer exists, so we hope regcache_raw_supply will do instead. */
 
 
  store_unsigned_integer (buf, sizeof (CORE_ADDR), val);
  store_unsigned_integer (buf, sizeof (CORE_ADDR), val);
  regcache_raw_supply (regcache, regnum, buf);
  regcache_raw_supply (regcache, regnum, buf);
 
 
}       /* or1k_fetch_registers() */
}       /* or1k_fetch_registers() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Store remote registers
/*!Store remote registers
 
 
   The remote registers are written from the register cache
   The remote registers are written from the register cache
 
 
   @param[in] regcache  The register cache to use
   @param[in] regcache  The register cache to use
   @param[in] regnum    The desired register number, or -1 if all are wanted */
   @param[in] regnum    The desired register number, or -1 if all are wanted */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_store_registers (struct regcache *regcache,
or1k_store_registers (struct regcache *regcache,
                      int              regnum)
                      int              regnum)
{
{
  ULONGEST         res;
  ULONGEST         res;
 
 
  if (-1 == regnum)
  if (-1 == regnum)
    {
    {
      for (regnum = 0; regnum < OR1K_NUM_REGS; regnum++)
      for (regnum = 0; regnum < OR1K_NUM_REGS; regnum++)
        {
        {
          or1k_store_registers (regcache, regnum);
          or1k_store_registers (regcache, regnum);
        }
        }
      return;
      return;
    }
    }
 
 
  if (regnum >= OR1K_NUM_REGS)
  if (regnum >= OR1K_NUM_REGS)
    {
    {
      error ("or1k_store_registers: invalid register number");
      error ("or1k_store_registers: invalid register number");
    }
    }
 
 
  regcache = get_current_regcache();
  regcache = get_current_regcache();
  regcache_cooked_read_unsigned (regcache, regnum, &res);
  regcache_cooked_read_unsigned (regcache, regnum, &res);
  or1k_jtag_write_spr (or1k_regnum_to_sprnum (regnum), res);
  or1k_jtag_write_spr (or1k_regnum_to_sprnum (regnum), res);
 
 
}       /* or1k_store_registers() */
}       /* or1k_store_registers() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Prepare to store registers
/*!Prepare to store registers
 
 
   This is a null function for the OpenRisc 1000 architecture
   This is a null function for the OpenRisc 1000 architecture
 
 
   @param[in] regcache  The register cache to use */
   @param[in] regcache  The register cache to use */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_prepare_to_store (struct regcache *regcache)
or1k_prepare_to_store (struct regcache *regcache)
{
{
  return;
  return;
 
 
}       /* or1k_prepare_to_store() */
}       /* or1k_prepare_to_store() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Transfer some data to or from the target
/*!Transfer some data to or from the target
 
 
   One and only one of readbuf or writebuf should be non-NULL, which indicates
   One and only one of readbuf or writebuf should be non-NULL, which indicates
   whether this is a read or write operation.
   whether this is a read or write operation.
 
 
   OR1K reads and writes are in words, so we may need to do partial
   OR1K reads and writes are in words, so we may need to do partial
   read/writes at each end of the transfer.
   read/writes at each end of the transfer.
 
 
   @param[in]  ops       The target_ops vector to use
   @param[in]  ops       The target_ops vector to use
   @param[in]  object    The type of object to transfer
   @param[in]  object    The type of object to transfer
   @param[in]  annex     Additional object specific information (not used)
   @param[in]  annex     Additional object specific information (not used)
   @param[out] readbuf   Buffer for read data
   @param[out] readbuf   Buffer for read data
   @param[in]  writebuf  Buffer of data to write
   @param[in]  writebuf  Buffer of data to write
   @param[in]  offset    Offset into object
   @param[in]  offset    Offset into object
   @param[in]  len       Max bytes to transer
   @param[in]  len       Max bytes to transer
 
 
   @return  Number of bytes transferred or -1 if not supported */
   @return  Number of bytes transferred or -1 if not supported */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
LONGEST  or1k_xfer_partial (struct target_ops  *ops,
LONGEST  or1k_xfer_partial (struct target_ops  *ops,
                                 enum target_object  object,
                                 enum target_object  object,
                                 const char         *annex,
                                 const char         *annex,
                                 gdb_byte           *readbuf,
                                 gdb_byte           *readbuf,
                                 const gdb_byte     *writebuf,
                                 const gdb_byte     *writebuf,
                                 ULONGEST            offset,
                                 ULONGEST            offset,
                                 LONGEST             len)
                                 LONGEST             len)
{
{
  /* Only memory transfer is currently supported */
  /* Only memory transfer is currently supported */
  if (TARGET_OBJECT_MEMORY != object)
  if (TARGET_OBJECT_MEMORY != object)
    {
    {
      return  -1;
      return  -1;
    }
    }
 
 
  if (NULL == writebuf)
  if (NULL == writebuf)
    {
    {
      /* Must be a read */
      /* Must be a read */
      gdb_assert (NULL != readbuf);
      gdb_assert (NULL != readbuf);
 
 
      return  or1k_jtag_read_mem (offset, readbuf, len);
      return  or1k_jtag_read_mem (offset, readbuf, len);
    }
    }
  else
  else
    {
    {
      return  or1k_jtag_write_mem (offset, writebuf, len);
      return  or1k_jtag_write_mem (offset, writebuf, len);
    }
    }
}       /* or1k_xfer_partial() */
}       /* or1k_xfer_partial() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Insert a breakpoint
/*!Insert a breakpoint
 
 
   Try to insert a breakpoint. Use hardware breakpoints if they are supported,
   Try to insert a breakpoint. Use hardware breakpoints if they are supported,
   software breakpoints otherwise.
   software breakpoints otherwise.
 
 
   @param[in] bpi  Break point info with details of the address and a cache to
   @param[in] bpi  Break point info with details of the address and a cache to
                   hold the existing memory value if overwriting.
                   hold the existing memory value if overwriting.
 
 
                   @return  0 if the breakpoint was set, non-zero otherwise */
                   @return  0 if the breakpoint was set, non-zero otherwise */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_insert_breakpoint (struct bp_target_info *bpi)
or1k_insert_breakpoint (struct bp_target_info *bpi)
{
{
  if (0 == or1k_set_breakpoint (bpi->placed_address))
  if (0 == or1k_set_breakpoint (bpi->placed_address))
    {
    {
      return 0;
      return 0;
    }
    }
  else
  else
    {
    {
      return  memory_insert_breakpoint (bpi);
      return  memory_insert_breakpoint (bpi);
    }
    }
}       /* or1k_insert_breakpoint() */
}       /* or1k_insert_breakpoint() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Remove a breakpoint
/*!Remove a breakpoint
 
 
   @param[in] bpi  Break point info with details of the address and a cache to
   @param[in] bpi  Break point info with details of the address and a cache to
                   hold the existing memory value if overwriting.
                   hold the existing memory value if overwriting.
 
 
                   @return  0 if the breakpoint was cleared, non-zero otherwise */
                   @return  0 if the breakpoint was cleared, non-zero otherwise */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_remove_breakpoint (struct bp_target_info *bpi)
or1k_remove_breakpoint (struct bp_target_info *bpi)
{
{
  /* First try to remove HW breakpoint at address */
  /* First try to remove HW breakpoint at address */
  if (0 != or1k_clear_breakpoint (bpi->placed_address))
  if (0 != or1k_clear_breakpoint (bpi->placed_address))
    {
    {
      return  memory_remove_breakpoint (bpi);
      return  memory_remove_breakpoint (bpi);
    }
    }
  else
  else
    {
    {
      return  0;
      return  0;
    }
    }
}       /* or1k_remove_breakpoint() */
}       /* or1k_remove_breakpoint() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Tell whether we can support a hardware breakpoint or watchpoint
/*!Tell whether we can support a hardware breakpoint or watchpoint
 
 
   There are only a fixed number of hardware breakpoints available. Check if
   There are only a fixed number of hardware breakpoints available. Check if
   there are any left. Hardware watchpoints need TWO matchpoints.
   there are any left. Hardware watchpoints need TWO matchpoints.
 
 
   This is only an approximation. An exact response would need full knowledge
   This is only an approximation. An exact response would need full knowledge
   of all the HW resources requested and would need to guarantee those
   of all the HW resources requested and would need to guarantee those
   resources were not subsequently cannabalized for non-HW breakpoints and
   resources were not subsequently cannabalized for non-HW breakpoints and
   watchpoints.
   watchpoints.
 
 
   The algorithm is to multiply count by 1 for breakpoints and 2 for
   The algorithm is to multiply count by 1 for breakpoints and 2 for
   watchpoints and add 2 if othertype is set. Any matchpoints already used are
   watchpoints and add 2 if othertype is set. Any matchpoints already used are
   ignored (we cannot know if they relate to the question currently being
   ignored (we cannot know if they relate to the question currently being
   asked). This approach means we will never reject when there is HW
   asked). This approach means we will never reject when there is HW
   breakpoint resource available, but we may sometimes accept when there turns
   breakpoint resource available, but we may sometimes accept when there turns
   out to be no HW resource available. But GDB handles that OK (see section
   out to be no HW resource available. But GDB handles that OK (see section
   5.1.2 in the user guide).
   5.1.2 in the user guide).
 
 
   @param[in] type       What type of matchpoint are we asking about? This
   @param[in] type       What type of matchpoint are we asking about? This
                         function is apparently only called for
                         function is apparently only called for
                         bp_hardware_watchpoint, bp_read_watchpoint,
                         bp_hardware_watchpoint, bp_read_watchpoint,
                         bp_write_watchpoint (but the enum is called
                         bp_write_watchpoint (but the enum is called
                         access_watchpoint) or bp_hardware_breakpoint
                         access_watchpoint) or bp_hardware_breakpoint
   @param[in] count      How many of this type of matchpoint have been used
   @param[in] count      How many of this type of matchpoint have been used
                         (including this one)
                         (including this one)
   @param[in] othertype  1 (true) if this is a call about a watchpoint and
   @param[in] othertype  1 (true) if this is a call about a watchpoint and
                         watchpoints (but not breakpoints) of other types have
                         watchpoints (but not breakpoints) of other types have
                         been set.
                         been set.
 
 
   @return  the number of watchpoints of this type that can be set if count
   @return  the number of watchpoints of this type that can be set if count
            watchpoints can be set, 0 if watchpoints of this type cannot be
            watchpoints can be set, 0 if watchpoints of this type cannot be
            set and negative if watchpoints of this type can be set, but there
            set and negative if watchpoints of this type can be set, but there
            are none available. */
            are none available. */
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
 
 
static int
static int
or1k_can_use_hw_matchpoint (int  type,
or1k_can_use_hw_matchpoint (int  type,
                            int  count,
                            int  count,
                            int  othertype)
                            int  othertype)
{
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
 
 
  switch (type)
  switch (type)
    {
    {
    case bp_hardware_breakpoint:
    case bp_hardware_breakpoint:
      if (count <= tdep->num_matchpoints)
      if (count <= tdep->num_matchpoints)
        {
        {
          return  tdep->num_matchpoints;
          return  tdep->num_matchpoints;
        }
        }
      else
      else
        {
        {
          return -1;
          return -1;
        }
        }
 
 
    case bp_hardware_watchpoint:
    case bp_hardware_watchpoint:
    case bp_read_watchpoint:
    case bp_read_watchpoint:
    case bp_access_watchpoint:
    case bp_access_watchpoint:
      if ((2 * (othertype + count)) <= tdep->num_matchpoints)
      if ((2 * (othertype + count)) <= tdep->num_matchpoints)
        {
        {
          return  tdep->num_matchpoints / (2 * (othertype + count));
          return  tdep->num_matchpoints / (2 * (othertype + count));
        }
        }
      else
      else
        {
        {
          return  -1;
          return  -1;
        }
        }
 
 
    default:
    default:
      warning( "Request to use unknown hardware matchpoint type: %d\n",
      warning( "Request to use unknown hardware matchpoint type: %d\n",
               type );
               type );
      return  0;
      return  0;
    }
    }
 
 
}       /* or1k_can_use_hw_matchpoint() */
}       /* or1k_can_use_hw_matchpoint() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Insert a hardware breakpoint
/*!Insert a hardware breakpoint
 
 
   Try to insert a hardware breakpoint if they are supported.
   Try to insert a hardware breakpoint if they are supported.
 
 
   @param[in] bpi  Break point info with details of the address and a cache to
   @param[in] bpi  Break point info with details of the address and a cache to
                   hold the existing memory value if overwriting.
                   hold the existing memory value if overwriting.
 
 
                   @return  0 if the breakpoint was set, non-zero otherwise */
                   @return  0 if the breakpoint was set, non-zero otherwise */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_insert_hw_breakpoint (struct bp_target_info *bpi)
or1k_insert_hw_breakpoint (struct bp_target_info *bpi)
{
{
  return  or1k_set_breakpoint (bpi->placed_address);
  return  or1k_set_breakpoint (bpi->placed_address);
 
 
}       /* or1k_insert_hw_breakpoint() */
}       /* or1k_insert_hw_breakpoint() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Remove a hardware breakpoint
/*!Remove a hardware breakpoint
 
 
   @param[in] bpi  Break point info with details of the address and a cache to
   @param[in] bpi  Break point info with details of the address and a cache to
                   hold the existing memory value if overwriting.
                   hold the existing memory value if overwriting.
 
 
                   @return  0 if the breakpoint was cleared, non-zero otherwise */
                   @return  0 if the breakpoint was cleared, non-zero otherwise */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_remove_hw_breakpoint (struct bp_target_info *bpi)
or1k_remove_hw_breakpoint (struct bp_target_info *bpi)
{
{
  return  or1k_clear_breakpoint (bpi->placed_address);
  return  or1k_clear_breakpoint (bpi->placed_address);
 
 
}       /* or1k_remove_hw_breakpoint() */
}       /* or1k_remove_hw_breakpoint() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set a data watchpoint.
/*!Set a data watchpoint.
 
 
   A GDB data watchpoint uses a pair of HW watchpoints. The first looks for
   A GDB data watchpoint uses a pair of HW watchpoints. The first looks for
   accesses greater than or equal to the start address, the second looks for
   accesses greater than or equal to the start address, the second looks for
   accesses less than or equal to the end address. This allows watching of any
   accesses less than or equal to the end address. This allows watching of any
   length of object.
   length of object.
 
 
   However because of the way the OpenRISC 1000 chains its watchpoints, a
   However because of the way the OpenRISC 1000 chains its watchpoints, a
   suitable adjacent pair must be found. So the watchpoint garbage collector
   suitable adjacent pair must be found. So the watchpoint garbage collector
   is used to shuffle them all up.
   is used to shuffle them all up.
 
 
   @param[in] addr  Address to be watched
   @param[in] addr  Address to be watched
   @param[in] len   Length of the entity to be watched
   @param[in] len   Length of the entity to be watched
   @param[in] type  hw_write (0) for a write watchpoint, hw_read (1) for a
   @param[in] type  hw_write (0) for a write watchpoint, hw_read (1) for a
                    read watchpoint, or hw_access (2) for a read/write
                    read watchpoint, or hw_access (2) for a read/write
                    watchpoint.
                    watchpoint.
 
 
   @return  0 if the watchpoint was set, -1 otherwise (it must be -1, not just
   @return  0 if the watchpoint was set, -1 otherwise (it must be -1, not just
   any non-zero number, since breakpoint.c tests explicitly for -1 */
   any non-zero number, since breakpoint.c tests explicitly for -1 */
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
 
 
static int
static int
or1k_insert_watchpoint (CORE_ADDR  addr,
or1k_insert_watchpoint (CORE_ADDR  addr,
                        int        len,
                        int        len,
                        int        type)
                        int        type)
{
{
  unsigned char        dcr_ct = or1k_gdb_to_dcr_type (type);
  unsigned char        dcr_ct = or1k_gdb_to_dcr_type (type);
  int                  first_free;
  int                  first_free;
 
 
  if (len < 1)
  if (len < 1)
    {
    {
      return  -1;
      return  -1;
    }
    }
 
 
  /* Garbage collect and see if we have two adjacent watchpoints available. */
  /* Garbage collect and see if we have two adjacent watchpoints available. */
 
 
  if( or1k_watchpoint_gc() < 2 )
  if( or1k_watchpoint_gc() < 2 )
    {
    {
      return  -1;
      return  -1;
    }
    }
 
 
 
 
  /* Set lower bound at first free matchpoint. */
  /* Set lower bound at first free matchpoint. */
  first_free               = or1k_first_free_matchpoint();
  first_free               = or1k_first_free_matchpoint();
 
 
  or1k_dbgcache.dvr[first_free]     = addr;
  or1k_dbgcache.dvr[first_free]     = addr;
  or1k_dbgcache.dcr[first_free].dp  = 1;
  or1k_dbgcache.dcr[first_free].dp  = 1;
  or1k_dbgcache.dcr[first_free].cc  = OR1K_CC_GE;
  or1k_dbgcache.dcr[first_free].cc  = OR1K_CC_GE;
  or1k_dbgcache.dcr[first_free].sc  = 0;
  or1k_dbgcache.dcr[first_free].sc  = 0;
  or1k_dbgcache.dcr[first_free].ct  = dcr_ct;
  or1k_dbgcache.dcr[first_free].ct  = dcr_ct;
 
 
  /* Set upper watchpoint bound at next matchpoint. GC guarantees
  /* Set upper watchpoint bound at next matchpoint. GC guarantees
     it is free. */
     it is free. */
  first_free++;
  first_free++;
 
 
  or1k_dbgcache.dvr[first_free]     = addr + len - 1;
  or1k_dbgcache.dvr[first_free]     = addr + len - 1;
  or1k_dbgcache.dcr[first_free].dp  = 1;
  or1k_dbgcache.dcr[first_free].dp  = 1;
  or1k_dbgcache.dcr[first_free].cc  = OR1K_CC_LE;
  or1k_dbgcache.dcr[first_free].cc  = OR1K_CC_LE;
  or1k_dbgcache.dcr[first_free].sc  = 0;
  or1k_dbgcache.dcr[first_free].sc  = 0;
  or1k_dbgcache.dcr[first_free].ct  = dcr_ct;
  or1k_dbgcache.dcr[first_free].ct  = dcr_ct;
 
 
  /* Set && chaining of the second matchpoint to the first. This is the only
  /* Set && chaining of the second matchpoint to the first. This is the only
     one which should generate a breakpoint, since it only occurs when BOTH
     one which should generate a breakpoint, since it only occurs when BOTH
     matchpoints trigger. */
     matchpoints trigger. */
  or1k_dbgcache.dmr1 &= ~(OR1K_DMR1_CW     << (OR1K_DMR1_CW_SZ * first_free));
  or1k_dbgcache.dmr1 &= ~(OR1K_DMR1_CW     << (OR1K_DMR1_CW_SZ * first_free));
  or1k_dbgcache.dmr1 |=  (OR1K_DMR1_CW_AND << (OR1K_DMR1_CW_SZ * first_free));
  or1k_dbgcache.dmr1 |=  (OR1K_DMR1_CW_AND << (OR1K_DMR1_CW_SZ * first_free));
  or1k_dbgcache.dmr2 |= (1 << (first_free + OR1K_DMR2_WGB_OFF));
  or1k_dbgcache.dmr2 |= (1 << (first_free + OR1K_DMR2_WGB_OFF));
 
 
  return 0;
  return 0;
 
 
}       /* or1k_insert_watchpoint() */
}       /* or1k_insert_watchpoint() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Remove a data watchpoint.
/*!Remove a data watchpoint.
 
 
   @param[in] addr  Address being watched
   @param[in] addr  Address being watched
   @param[in] len   Length of the entity being watched
   @param[in] len   Length of the entity being watched
   @param[in] type  0 for a write watchpoint, 1 for a read watchpoint, or 2
   @param[in] type  0 for a write watchpoint, 1 for a read watchpoint, or 2
                    for a read/write watchpoint
                    for a read/write watchpoint
 
 
                    @return  0 if the watchpoint was cleared, non-zero otherwise */
                    @return  0 if the watchpoint was cleared, non-zero otherwise */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_remove_watchpoint (CORE_ADDR  addr,
or1k_remove_watchpoint (CORE_ADDR  addr,
                        int        len,
                        int        len,
                        int        type)
                        int        type)
{
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  unsigned char        dcr_ct;
  unsigned char        dcr_ct;
  CORE_ADDR            end_addr;
  CORE_ADDR            end_addr;
  int                  mp;
  int                  mp;
 
 
  if (len < 1)
  if (len < 1)
    {
    {
      return -1;
      return -1;
    }
    }
 
 
  dcr_ct   = or1k_gdb_to_dcr_type (type);
  dcr_ct   = or1k_gdb_to_dcr_type (type);
  end_addr = addr + len - 1;
  end_addr = addr + len - 1;
 
 
  /* Find the right one. PS. Don't be tempted to compare mp against
  /* Find the right one. PS. Don't be tempted to compare mp against
     tdep->num_matchpoints - 1. It's unsigned and can be 0, so you'd go
     tdep->num_matchpoints - 1. It's unsigned and can be 0, so you'd go
     on for ever! */
     on for ever! */
  for (mp = 0; (mp + 1) < tdep->num_matchpoints; mp++)
  for (mp = 0; (mp + 1) < tdep->num_matchpoints; mp++)
    {
    {
      if (or1k_matchpoint_equal( mp,     addr,     OR1K_CC_GE, 0, dcr_ct) &&
      if (or1k_matchpoint_equal( mp,     addr,     OR1K_CC_GE, 0, dcr_ct) &&
          or1k_matchpoint_equal( mp + 1, end_addr, OR1K_CC_LE, 0, dcr_ct))
          or1k_matchpoint_equal( mp + 1, end_addr, OR1K_CC_LE, 0, dcr_ct))
        {
        {
          break;
          break;
        }
        }
    }
    }
 
 
  if ((mp + 1) >= tdep->num_matchpoints)
  if ((mp + 1) >= tdep->num_matchpoints)
    {
    {
      return -1;
      return -1;
    }
    }
 
 
  /* Mark each matchpoint unused and clear the bits for the second watchpoint
  /* Mark each matchpoint unused and clear the bits for the second watchpoint
     in the assign to counter, watchpoint generating break and breakpoint
     in the assign to counter, watchpoint generating break and breakpoint
     status bits in DMR2. */
     status bits in DMR2. */
 
 
  or1k_dbgcache.dcr[mp].dp = 0;
  or1k_dbgcache.dcr[mp].dp = 0;
 
 
  mp++;
  mp++;
  or1k_dbgcache.dcr[mp].dp = 0;
  or1k_dbgcache.dcr[mp].dp = 0;
  or1k_dbgcache.dmr2 &= ~(1 << (mp + OR1K_DMR2_AWTC_OFF));
  or1k_dbgcache.dmr2 &= ~(1 << (mp + OR1K_DMR2_AWTC_OFF));
  or1k_dbgcache.dmr2 &= ~(1 << (mp + OR1K_DMR2_WGB_OFF));
  or1k_dbgcache.dmr2 &= ~(1 << (mp + OR1K_DMR2_WGB_OFF));
  or1k_dbgcache.dmr2 &= ~(1 << (mp + OR1K_DMR2_WBS_OFF));
  or1k_dbgcache.dmr2 &= ~(1 << (mp + OR1K_DMR2_WBS_OFF));
 
 
  return 0;
  return 0;
 
 
}       /* or1k_remove_watchpoint() */
}       /* or1k_remove_watchpoint() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Report if we stopped due to a watchpoint
/*!Report if we stopped due to a watchpoint
 
 
   All the information is calculated by or1k_stopped_data_address, so we must
   All the information is calculated by or1k_stopped_data_address, so we must
   reuse that.
   reuse that.
 
 
   @return  1 (true) if we were stopped by a watchpoint, 0 (false) otherwise */
   @return  1 (true) if we were stopped by a watchpoint, 0 (false) otherwise */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_stopped_by_watchpoint()
or1k_stopped_by_watchpoint()
{
{
  return  or1k_stopped_watchpoint_info (NULL, NULL);
  return  or1k_stopped_watchpoint_info (NULL, NULL);
 
 
}       /* or1k_stopped_by_watchpoint() */
}       /* or1k_stopped_by_watchpoint() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Address for which we were stopped by a remote watchpoint
/*!Address for which we were stopped by a remote watchpoint
 
 
   This is true if a triggered breakpoint was ANDed with the previous
   This is true if a triggered breakpoint was ANDed with the previous
   watchpoint in the chain. If so, the previous matchpoint has the start
   watchpoint in the chain. If so, the previous matchpoint has the start
   address.
   address.
 
 
   This function is called once when a watchpoint is hit, and must clear the
   This function is called once when a watchpoint is hit, and must clear the
   watchpoint status
   watchpoint status
 
 
   @param[in]  target  The target_ops we are using. Not clear why we need
   @param[in]  target  The target_ops we are using. Not clear why we need
                       this!
                       this!
   @param[out] addr_p  Where to put the address associated with the
   @param[out] addr_p  Where to put the address associated with the
                       watchpoint.
                       watchpoint.
 
 
                       @return  1 (true) if we get the address, 0 (false) otherwise */
                       @return  1 (true) if we get the address, 0 (false) otherwise */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_stopped_data_address (struct target_ops *target,
or1k_stopped_data_address (struct target_ops *target,
                           CORE_ADDR         *addr_p)
                           CORE_ADDR         *addr_p)
{
{
  int  mp;
  int  mp;
 
 
  /* Clear the result info if there was a watchpoint */
  /* Clear the result info if there was a watchpoint */
  if( or1k_stopped_watchpoint_info (addr_p, &mp))
  if( or1k_stopped_watchpoint_info (addr_p, &mp))
    {
    {
      or1k_dbgcache.dmr2 &= ~(1 << (mp + OR1K_DMR2_WBS_OFF));
      or1k_dbgcache.dmr2 &= ~(1 << (mp + OR1K_DMR2_WBS_OFF));
      return  1;
      return  1;
    }
    }
  else
  else
    {
    {
      return  0;
      return  0;
    }
    }
}       /* or1k_stopped_data_address() */
}       /* or1k_stopped_data_address() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Can we put a HW watchpoint of the given size at the given address
/*!Can we put a HW watchpoint of the given size at the given address
 
 
   We can always use a HW watchpoint, so long as there are HW watchpoints
   We can always use a HW watchpoint, so long as there are HW watchpoints
   available. This doesn't have to check availablility (see
   available. This doesn't have to check availablility (see
   or1k_can_use_hw_matchpoint().
   or1k_can_use_hw_matchpoint().
 
 
   @param[in] addr  The address of interest
   @param[in] addr  The address of interest
   @param[in] len   The length of the region to watch
   @param[in] len   The length of the region to watch
 
 
   @return  1 (true) to indicate we always can do a HW watchpoint */
   @return  1 (true) to indicate we always can do a HW watchpoint */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static int
static int
or1k_region_ok_for_hw_watchpoint (CORE_ADDR  addr,
or1k_region_ok_for_hw_watchpoint (CORE_ADDR  addr,
                                  int        len)
                                  int        len)
{
{
  return  1;
  return  1;
 
 
}       /* or1k_region_ok_for_hw_watchpoint */
}       /* or1k_region_ok_for_hw_watchpoint */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Resume execution of the target process.
/*!Resume execution of the target process.
 
 
   "step" says whether to single-step or to run free; "siggnal" is the signal
   "step" says whether to single-step or to run free; "siggnal" is the signal
   value (e.g. SIGINT) to be given to the target, or zero for no signal.
   value (e.g. SIGINT) to be given to the target, or zero for no signal.
 
 
   When we enter this routine the target should be stalled.
   When we enter this routine the target should be stalled.
 
 
   In general GDB sorts out issues of restarting across breakpoints. However
   In general GDB sorts out issues of restarting across breakpoints. However
   have to deal with the special case where a breakpoint occurred in the delay
   have to deal with the special case where a breakpoint occurred in the delay
   slot of a branch instruction. In this case the branch should be restarted,
   slot of a branch instruction. In this case the branch should be restarted,
   BUT ONLY if the branch had originally been executed.
   BUT ONLY if the branch had originally been executed.
 
 
   For now we ignore this case (it really is very hard.
   For now we ignore this case (it really is very hard.
 
 
   @param[in]  ptid  The process or thread ID - ignored here
   @param[in]  ptid  The process or thread ID - ignored here
   @param[in]  step  If true (1) single step the target
   @param[in]  step  If true (1) single step the target
   @param[in]  sig   Signal to give to the target */
   @param[in]  sig   Signal to give to the target */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_resume (ptid_t              ptid,
or1k_resume (ptid_t              ptid,
             int                 step,
             int                 step,
             enum target_signal  sig)
             enum target_signal  sig)
{
{
  /* Note if we are single stepping. For use when waiting */
  /* Note if we are single stepping. For use when waiting */
  or1k_is_single_stepping = step;
  or1k_is_single_stepping = step;
 
 
  /* The debug reason register and the watchpoint break status
  /* The debug reason register and the watchpoint break status
     are both cleared before resuming. */
     are both cleared before resuming. */
  or1k_dbgcache.drr   = 0;
  or1k_dbgcache.drr   = 0;
  or1k_dbgcache.dmr2 &= ~OR1K_DMR2_WBS_MASK;
  or1k_dbgcache.dmr2 &= ~OR1K_DMR2_WBS_MASK;
 
 
  /* Set single stepping if required */
  /* Set single stepping if required */
  if (step)
  if (step)
    {
    {
      or1k_dbgcache.dmr1 |= OR1K_DMR1_ST;
      or1k_dbgcache.dmr1 |= OR1K_DMR1_ST;
    }
    }
  else
  else
    {
    {
      or1k_dbgcache.dmr1 &= ~OR1K_DMR1_ST;
      or1k_dbgcache.dmr1 &= ~OR1K_DMR1_ST;
    }
    }
 
 
  or1k_commit_debug_registers();
  or1k_commit_debug_registers();
 
 
  /* We can now continue normally, independent of step. If this is called for
  /* We can now continue normally, independent of step. If this is called for
     the first time due to a run command, we won't actually be executing, so
     the first time due to a run command, we won't actually be executing, so
     start the target running. */
     start the target running. */
 
 
  or1k_jtag_write_spr( OR1K_NPC_SPRNUM, read_pc());
  or1k_jtag_write_spr( OR1K_NPC_SPRNUM, read_pc());
  target_has_execution = 1;
  target_has_execution = 1;
  or1k_jtag_unstall ();
  or1k_jtag_unstall ();
 
 
}       /* or1k_resume() */
}       /* or1k_resume() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Wait until the remote server stops, and return a wait status.
/*!Wait until the remote server stops, and return a wait status.
 
 
   Seems to assume that the remote target is identified solely by PID with no
   Seems to assume that the remote target is identified solely by PID with no
   thread or lightweight thread component.
   thread or lightweight thread component.
 
 
   This is mostly a case of just sorting out the type of exception. GDB will
   This is mostly a case of just sorting out the type of exception. GDB will
   automatically sort out restarting with breakpoints removed etc.
   automatically sort out restarting with breakpoints removed etc.
 
 
   @note The old code differentiated a high priority and a low priority
   @note The old code differentiated a high priority and a low priority
         interrupt, which no longer exists on the OR1K. The old code also
         interrupt, which no longer exists on the OR1K. The old code also
         omitted tick timer and floating point exceptions, which have been
         omitted tick timer and floating point exceptions, which have been
         added.
         added.
 
 
   @param[in]  remote_ptid  The process/thread ID of the remote target
   @param[in]  remote_ptid  The process/thread ID of the remote target
   @param[out] status       Status of the waiting process
   @param[out] status       Status of the waiting process
 
 
   @return  The remote_ptid unchanged */
   @return  The remote_ptid unchanged */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static ptid_t
static ptid_t
or1k_wait (ptid_t                    remote_ptid,
or1k_wait (ptid_t                    remote_ptid,
           struct target_waitstatus *status)
           struct target_waitstatus *status)
{
{
  unsigned long int  addr;
  unsigned long int  addr;
  char               buf[OR1K_INSTLEN];
  char               buf[OR1K_INSTLEN];
  int                res;
  int                res;
 
 
  /* Set new signal handler (so we can interrupt with ctrl-C) and then wait
  /* Set new signal handler (so we can interrupt with ctrl-C) and then wait
     for the OR1K to stall. */
     for the OR1K to stall. */
  or1k_old_intr_handler = signal (SIGINT, or1k_interrupt);
  or1k_old_intr_handler = signal (SIGINT, or1k_interrupt);
  or1k_jtag_wait (or1k_is_single_stepping);
  or1k_jtag_wait (or1k_is_single_stepping);
  signal (SIGINT, or1k_old_intr_handler);
  signal (SIGINT, or1k_old_intr_handler);
 
 
  /* Registers and frame caches are now all unreliable */
  /* Registers and frame caches are now all unreliable */
  registers_changed();
  registers_changed();
 
 
  /* Refresh the debug registers that may have changed */
  /* Refresh the debug registers that may have changed */
  or1k_dbgcache.drr  = or1k_jtag_read_spr (OR1K_DRR_SPRNUM);
  or1k_dbgcache.drr  = or1k_jtag_read_spr (OR1K_DRR_SPRNUM);
  or1k_dbgcache.dmr2 = or1k_jtag_read_spr (OR1K_DMR2_SPRNUM);
  or1k_dbgcache.dmr2 = or1k_jtag_read_spr (OR1K_DMR2_SPRNUM);
 
 
  /* If we got a trap, then it was a breakpoint/watchpoint of some sort (but
  /* If we got a trap, then it was a breakpoint/watchpoint of some sort (but
     not single step, which does not set the trap exception). We need to back
     not single step, which does not set the trap exception). We need to back
     up the program counter, so the instruction will be re-executed. This
     up the program counter, so the instruction will be re-executed. This
     must be the value of the PPC, in case we have just done a branch. */
     must be the value of the PPC, in case we have just done a branch. */
 
 
  if (OR1K_DRR_TE == (or1k_dbgcache.drr & OR1K_DRR_TE))
  if (OR1K_DRR_TE == (or1k_dbgcache.drr & OR1K_DRR_TE))
    {
    {
      write_pc (or1k_jtag_read_spr (OR1K_PPC_SPRNUM));
      write_pc (or1k_jtag_read_spr (OR1K_PPC_SPRNUM));
    }
    }
 
 
  /* Single step does not set trap exception, so we set it manually to
  /* Single step does not set trap exception, so we set it manually to
     simplify our code. */
     simplify our code. */
  if (OR1K_DMR1_ST == (or1k_dbgcache.dmr1 & OR1K_DMR1_ST))
  if (OR1K_DMR1_ST == (or1k_dbgcache.dmr1 & OR1K_DMR1_ST))
    {
    {
      or1k_dbgcache.drr |= OR1K_DRR_TE;
      or1k_dbgcache.drr |= OR1K_DRR_TE;
    }
    }
 
 
  status->kind = TARGET_WAITKIND_STOPPED;
  status->kind = TARGET_WAITKIND_STOPPED;
 
 
  /* Map OR1K exception to GDB signal. If multiple signals are set, only the
  /* Map OR1K exception to GDB signal. If multiple signals are set, only the
     least significant in the DRR is used (the expression here yields the LSB
     least significant in the DRR is used (the expression here yields the LSB
     in a 2's complement machine) */
     in a 2's complement machine) */
  switch (or1k_dbgcache.drr & (-or1k_dbgcache.drr))
  switch (or1k_dbgcache.drr & (-or1k_dbgcache.drr))
    {
    {
    case OR1K_DRR_RSTE:  status->value.sig = TARGET_SIGNAL_PWR;  break;
    case OR1K_DRR_RSTE:  status->value.sig = TARGET_SIGNAL_PWR;  break;
    case OR1K_DRR_BUSEE: status->value.sig = TARGET_SIGNAL_BUS;  break;
    case OR1K_DRR_BUSEE: status->value.sig = TARGET_SIGNAL_BUS;  break;
    case OR1K_DRR_DPFE:  status->value.sig = TARGET_SIGNAL_SEGV; break;
    case OR1K_DRR_DPFE:  status->value.sig = TARGET_SIGNAL_SEGV; break;
    case OR1K_DRR_IPFE:  status->value.sig = TARGET_SIGNAL_SEGV; break;
    case OR1K_DRR_IPFE:  status->value.sig = TARGET_SIGNAL_SEGV; break;
    case OR1K_DRR_TTE:   status->value.sig = TARGET_SIGNAL_ALRM; break;
    case OR1K_DRR_TTE:   status->value.sig = TARGET_SIGNAL_ALRM; break;
    case OR1K_DRR_AE:    status->value.sig = TARGET_SIGNAL_BUS;  break;
    case OR1K_DRR_AE:    status->value.sig = TARGET_SIGNAL_BUS;  break;
    case OR1K_DRR_IIE:   status->value.sig = TARGET_SIGNAL_ILL;  break;
    case OR1K_DRR_IIE:   status->value.sig = TARGET_SIGNAL_ILL;  break;
    case OR1K_DRR_INTE:  status->value.sig = TARGET_SIGNAL_INT;  break;
    case OR1K_DRR_INTE:  status->value.sig = TARGET_SIGNAL_INT;  break;
    case OR1K_DRR_DME:   status->value.sig = TARGET_SIGNAL_SEGV; break;
    case OR1K_DRR_DME:   status->value.sig = TARGET_SIGNAL_SEGV; break;
    case OR1K_DRR_IME:   status->value.sig = TARGET_SIGNAL_SEGV; break;
    case OR1K_DRR_IME:   status->value.sig = TARGET_SIGNAL_SEGV; break;
    case OR1K_DRR_RE:    status->value.sig = TARGET_SIGNAL_FPE;  break;
    case OR1K_DRR_RE:    status->value.sig = TARGET_SIGNAL_FPE;  break;
    case OR1K_DRR_SCE:   status->value.sig = TARGET_SIGNAL_USR2; break;
    case OR1K_DRR_SCE:   status->value.sig = TARGET_SIGNAL_USR2; break;
    case OR1K_DRR_FPE:   status->value.sig = TARGET_SIGNAL_FPE;  break;
    case OR1K_DRR_FPE:   status->value.sig = TARGET_SIGNAL_FPE;  break;
    case OR1K_DRR_TE:    status->value.sig = TARGET_SIGNAL_TRAP; break;
    case OR1K_DRR_TE:    status->value.sig = TARGET_SIGNAL_TRAP; break;
 
 
    default:
    default:
      /* This just means the target stopped without raising any
      /* This just means the target stopped without raising any
         interrupt. This happens at reset and exit. The latter we distinquish
         interrupt. This happens at reset and exit. The latter we distinquish
         by looking at the instruction just executed, to see if it is
         by looking at the instruction just executed, to see if it is
         "l.nop NOP_EXIT". If this is the case, get the result from GPR 3 and
         "l.nop NOP_EXIT". If this is the case, get the result from GPR 3 and
         set the NPC to the reset vector, so a new start will behave well. */
         set the NPC to the reset vector, so a new start will behave well. */
 
 
      addr = or1k_jtag_read_spr (OR1K_PPC_SPRNUM);
      addr = or1k_jtag_read_spr (OR1K_PPC_SPRNUM);
      res  = read_memory_nobpt (addr, buf, OR1K_INSTLEN);
      res  = read_memory_nobpt (addr, buf, OR1K_INSTLEN);
      if (0 != res)
      if (0 != res)
        {
        {
          memory_error (res, addr);
          memory_error (res, addr);
        }
        }
 
 
      if (OR1K_NOP_EXIT ==
      if (OR1K_NOP_EXIT ==
          (unsigned long int)(extract_unsigned_integer (buf, OR1K_INSTLEN)))
          (unsigned long int)(extract_unsigned_integer (buf, OR1K_INSTLEN)))
        {
        {
          ULONGEST  val;
          ULONGEST  val;
 
 
          regcache_cooked_read_unsigned(get_current_regcache(),
          regcache_cooked_read_unsigned(get_current_regcache(),
                                        OR1K_FIRST_ARG_REGNUM, &val);
                                        OR1K_FIRST_ARG_REGNUM, &val);
          status->value.integer = val;
          status->value.integer = val;
          status->kind          = TARGET_WAITKIND_EXITED;
          status->kind          = TARGET_WAITKIND_EXITED;
          write_pc (OR1K_RESET_VECTOR);
          write_pc (OR1K_RESET_VECTOR);
        }
        }
      else
      else
        {
        {
          status->value.sig     = TARGET_SIGNAL_DEFAULT;
          status->value.sig     = TARGET_SIGNAL_DEFAULT;
        }
        }
      break;
      break;
    }
    }
 
 
  /* Clear the reason register */
  /* Clear the reason register */
  or1k_dbgcache.drr = 0;
  or1k_dbgcache.drr = 0;
 
 
  return remote_ptid;
  return remote_ptid;
 
 
}       /* or1k_wait() */
}       /* or1k_wait() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Stop the remote process
/*!Stop the remote process
 
 
   This is the generic stop called via the target vector. When a target
   This is the generic stop called via the target vector. When a target
   interrupt is requested, either by the command line or the GUI, we will
   interrupt is requested, either by the command line or the GUI, we will
   eventually end up here.
   eventually end up here.
 
 
   Just stall the processor, put it into single step mode and unstall. */
   Just stall the processor, put it into single step mode and unstall. */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_stop ()
or1k_stop ()
{
{
  /* We should not stop the target immediately, since it can be in an
  /* We should not stop the target immediately, since it can be in an
     unfinished state.  So we do a single step.  This should not affect
     unfinished state.  So we do a single step.  This should not affect
     anything.  */
     anything.  */
  or1k_jtag_stall();
  or1k_jtag_stall();
 
 
  /* HW STEP.  Set OR1K_DMR1_ST.  */
  /* HW STEP.  Set OR1K_DMR1_ST.  */
  or1k_dbgcache.dmr1 |= OR1K_DMR1_ST;
  or1k_dbgcache.dmr1 |= OR1K_DMR1_ST;
  or1k_commit_debug_registers();
  or1k_commit_debug_registers();
 
 
  or1k_jtag_unstall();
  or1k_jtag_unstall();
 
 
}       /* or1k_stop () */
}       /* or1k_stop () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Kill the process running on the board
/*!Kill the process running on the board
 
 
   We just ignore the target. Mourning the inferior will cause the connection
   We just ignore the target. Mourning the inferior will cause the connection
   to be closed. */
   to be closed. */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_kill ()
or1k_kill ()
{
{
  or1k_mourn_inferior ();
  or1k_mourn_inferior ();
 
 
}       /* or1k_kill () */
}       /* or1k_kill () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Start running on the target board by creating an inferior process
/*!Start running on the target board by creating an inferior process
 
 
   @param[in] execfile  What to run
   @param[in] execfile  What to run
   @param[in] args      Arguments to pass to the inferior process
   @param[in] args      Arguments to pass to the inferior process
   @param[in] env       Environment for the inferior process
   @param[in] env       Environment for the inferior process
   @param[in] from_tty  1 (true) if this session can write to the terminal */
   @param[in] from_tty  1 (true) if this session can write to the terminal */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_create_inferior (char  *execfile,
or1k_create_inferior (char  *execfile,
                      char  *args,
                      char  *args,
                      char **env,
                      char **env,
                      int    from_tty)
                      int    from_tty)
{
{
  CORE_ADDR entry_pt;
  CORE_ADDR entry_pt;
 
 
  if ((NULL != args) && ('\0' != args[0]))
  if ((NULL != args) && ('\0' != args[0]))
    {
    {
      warning ("or1k_create_inferior: "
      warning ("or1k_create_inferior: "
               "can't pass arguments to remote OR1K board - ignored");
               "can't pass arguments to remote OR1K board - ignored");
 
 
      /* And don't try to use them on the next "run" command.  */
      /* And don't try to use them on the next "run" command.  */
      execute_command ("set args", from_tty);
      execute_command ("set args", from_tty);
    }
    }
 
 
  if ((NULL == execfile) || (NULL == exec_bfd))
  if ((NULL == execfile) || (NULL == exec_bfd))
    {
    {
      warning (
      warning (
        "or1k_create_inferior: no executable file symbols specified\n"
        "or1k_create_inferior: no executable file symbols specified\n"
        "execution will proceed without symbol table. Use the \"file\"\n"
        "execution will proceed without symbol table. Use the \"file\"\n"
        "command to rectify this.\n");
        "command to rectify this.\n");
    }
    }
 
 
  /* The code won't actually start executing until it is unstalled in
  /* The code won't actually start executing until it is unstalled in
     or1k_resume(), so we'll call target_mark_running() there. Tidy up from
     or1k_resume(), so we'll call target_mark_running() there. Tidy up from
     last time we were running. */
     last time we were running. */
  init_wait_for_inferior ();
  init_wait_for_inferior ();
 
 
}       /* or1k_create_inferior () */
}       /* or1k_create_inferior () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Mourn the inferior process
/*!Mourn the inferior process
 
 
   We don't atually want to unpush the target - we should be able to call run
   We don't atually want to unpush the target - we should be able to call run
   again to restart it. Use the generic mourn and mark it as exited (it it was
   again to restart it. Use the generic mourn and mark it as exited (it it was
   running). */
   running). */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void
static void
or1k_mourn_inferior ()
or1k_mourn_inferior ()
{
{
  generic_mourn_inferior ();
  generic_mourn_inferior ();
 
 
  if( target_has_execution )
  if( target_has_execution )
    {
    {
      target_mark_exited (&or1k_target);
      target_mark_exited (&or1k_target);
    }
    }
}       /* or1k_mourn_inferior () */
}       /* or1k_mourn_inferior () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Send a command to the remote target
/*!Send a command to the remote target
 
 
   The target can't actually run any remote commands, in the sense of having a
   The target can't actually run any remote commands, in the sense of having a
   command interpreter. However we use this as a GDB "standard" way of
   command interpreter. However we use this as a GDB "standard" way of
   wrapping up commands to access the SPRs.
   wrapping up commands to access the SPRs.
 
 
   Current commands supported are:
   Current commands supported are:
   - readspr  <regno>
   - readspr  <regno>
   - writespr <regno> <value>
   - writespr <regno> <value>
 
 
   The output is either the value read (for successful read) or OK (for
   The output is either the value read (for successful read) or OK (for
   successful write) or E01 to indicate and wrror. All values are represented
   successful write) or E01 to indicate and wrror. All values are represented
   as unsigned hex.
   as unsigned hex.
 
 
   @param[in]  command  The command to execute
   @param[in]  command  The command to execute
   @param[out] output   The result of the command                            */
   @param[out] output   The result of the command                            */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
static void  or1k_rcmd (char           *command,
static void  or1k_rcmd (char           *command,
                        struct ui_file *outbuf)
                        struct ui_file *outbuf)
{
{
  /* Sort out which command */
  /* Sort out which command */
  if (0 == strncmp ("readspr", command, strlen ("readspr")))
  if (0 == strncmp ("readspr", command, strlen ("readspr")))
    {
    {
      unsigned int  regno;              /* SPR to read */
      unsigned int  regno;              /* SPR to read */
 
 
      if (1 != sscanf (command, "readspr %4x", &regno))
      if (1 != sscanf (command, "readspr %4x", &regno))
        {
        {
          error ("or1k_rcmd: unrecognized readspr");
          error ("or1k_rcmd: unrecognized readspr");
          fputs_unfiltered ("E01", outbuf);
          fputs_unfiltered ("E01", outbuf);
        }
        }
      else
      else
        {
        {
          char      strbuf[sizeof ("ffffffff")];
          char      strbuf[sizeof ("ffffffff")];
          ULONGEST  data = or1k_jtag_read_spr (regno);
          ULONGEST  data = or1k_jtag_read_spr (regno);
 
 
          sprintf (strbuf, "%8llx", (long long unsigned int)data);
          sprintf (strbuf, "%8llx", (long long unsigned int)data);
          fputs_unfiltered (strbuf, outbuf);
          fputs_unfiltered (strbuf, outbuf);
        }
        }
    }
    }
  else if (0 == strncmp ("writespr", command, strlen ("writespr")))
  else if (0 == strncmp ("writespr", command, strlen ("writespr")))
    {
    {
      unsigned int  regno;              /* SPR to write */
      unsigned int  regno;              /* SPR to write */
      long long unsigned int      data;         /* Value to write */
      long long unsigned int      data;         /* Value to write */
 
 
      if (2 != sscanf (command, "writespr %4x %8llx", &regno, &data))
      if (2 != sscanf (command, "writespr %4x %8llx", &regno, &data))
        {
        {
          error ("or1k_rcmd: unrecognized writespr");
          error ("or1k_rcmd: unrecognized writespr");
          fputs_unfiltered ("E01", outbuf);
          fputs_unfiltered ("E01", outbuf);
        }
        }
      else
      else
        {
        {
          or1k_jtag_write_spr (regno, data);
          or1k_jtag_write_spr (regno, data);
          fputs_unfiltered ("OK", outbuf);
          fputs_unfiltered ("OK", outbuf);
        }
        }
    }
    }
  else
  else
    {
    {
      error ("or1k_rcmd: unrecognized remote command");
      error ("or1k_rcmd: unrecognized remote command");
      fputs_unfiltered ("E01", outbuf);
      fputs_unfiltered ("E01", outbuf);
    }
    }
}       /* or1k_rcmd () */
}       /* or1k_rcmd () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Main entry point for the remote OpenRISC JTAG protocol
/*!Main entry point for the remote OpenRISC JTAG protocol
 
 
   Initializes the target ops for each version of the remote
   Initializes the target ops for each version of the remote
   protocol. Currently only the JTAG protocol is implemented.
   protocol. Currently only the JTAG protocol is implemented.
 
 
   @note Earlier versions of this code provided for a "sim" and "dummy"
   @note Earlier versions of this code provided for a "sim" and "dummy"
         target. However these never had any functionality, so have been
         target. However these never had any functionality, so have been
         deleted.
         deleted.
 
 
         @return  New CRC */
         @return  New CRC */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
 
 
  void
  void
_initialize_remote_or1k()
_initialize_remote_or1k()
{
{
  /* Set up the JTAG ops. */
  /* Set up the JTAG ops. */
 
 
  or1k_target.to_shortname                   = "jtag";
  or1k_target.to_shortname                   = "jtag";
  or1k_target.to_longname                    =
  or1k_target.to_longname                    =
    "OpenRISC 1000 debugging over JTAG port";
    "OpenRISC 1000 debugging over JTAG port";
  or1k_target.to_doc                         =
  or1k_target.to_doc                         =
    "Debug a board using the OpenRISC 1000 JTAG debugging protocol. The\n"
    "Debug a board using the OpenRISC 1000 JTAG debugging protocol. The\n"
    "target may be connected directly via the parallel port, or may be a\n"
    "target may be connected directly via the parallel port, or may be a\n"
    "remote connection over TCP/IP to another machine, an instance of the\n"
    "remote connection over TCP/IP to another machine, an instance of the\n"
    "Or1ksim architectural simulator, or physical hardware connected by USB\n"
    "Or1ksim architectural simulator, or physical hardware connected by USB\n"
    "with its own standalone control program.\n"
    "with its own standalone control program.\n"
    "\n"
    "\n"
    "The argument is the parallel port device (e.g. /dev/jp) to which it is\n"
    "The argument is the parallel port device (e.g. /dev/jp) to which it is\n"
    "connected locally or a URL of the form jtag://<hostname>:<port> or\n"
    "connected locally or a URL of the form jtag://<hostname>:<port> or\n"
    "jtag://<hostname>:<service> identifying the remote connection.";
    "jtag://<hostname>:<service> identifying the remote connection.";
 
 
  or1k_target.to_files_info                  = or1k_files_info;
  or1k_target.to_files_info                  = or1k_files_info;
  or1k_target.to_stratum                     = process_stratum;
  or1k_target.to_stratum                     = process_stratum;
  or1k_target.to_has_all_memory              = 1;
  or1k_target.to_has_all_memory              = 1;
  or1k_target.to_has_memory                  = 1;
  or1k_target.to_has_memory                  = 1;
  or1k_target.to_has_stack                   = 1;
  or1k_target.to_has_stack                   = 1;
  or1k_target.to_has_registers               = 1;
  or1k_target.to_has_registers               = 1;
  or1k_target.to_has_execution               = 0;
  or1k_target.to_has_execution               = 0;
  or1k_target.to_have_steppable_watchpoint   = 0;
  or1k_target.to_have_steppable_watchpoint   = 0;
  or1k_target.to_have_continuable_watchpoint = 0;
  or1k_target.to_have_continuable_watchpoint = 0;
 
 
  or1k_target.to_open                        = or1k_open;
  or1k_target.to_open                        = or1k_open;
  or1k_target.to_close                       = or1k_close;
  or1k_target.to_close                       = or1k_close;
  or1k_target.to_detach                      = or1k_detach;
  or1k_target.to_detach                      = or1k_detach;
 
 
  or1k_target.to_fetch_registers             = or1k_fetch_registers;
  or1k_target.to_fetch_registers             = or1k_fetch_registers;
  or1k_target.to_store_registers             = or1k_store_registers;
  or1k_target.to_store_registers             = or1k_store_registers;
  or1k_target.to_prepare_to_store            = or1k_prepare_to_store;
  or1k_target.to_prepare_to_store            = or1k_prepare_to_store;
  or1k_target.to_load                        = generic_load;
  or1k_target.to_load                        = generic_load;
  or1k_target.to_xfer_partial                = or1k_xfer_partial;
  or1k_target.to_xfer_partial                = or1k_xfer_partial;
 
 
  or1k_target.to_insert_breakpoint           = or1k_insert_breakpoint;
  or1k_target.to_insert_breakpoint           = or1k_insert_breakpoint;
  or1k_target.to_remove_breakpoint           = or1k_remove_breakpoint;
  or1k_target.to_remove_breakpoint           = or1k_remove_breakpoint;
  or1k_target.to_can_use_hw_breakpoint       = or1k_can_use_hw_matchpoint;
  or1k_target.to_can_use_hw_breakpoint       = or1k_can_use_hw_matchpoint;
  or1k_target.to_insert_hw_breakpoint        = or1k_insert_hw_breakpoint;
  or1k_target.to_insert_hw_breakpoint        = or1k_insert_hw_breakpoint;
  or1k_target.to_remove_hw_breakpoint        = or1k_remove_hw_breakpoint;
  or1k_target.to_remove_hw_breakpoint        = or1k_remove_hw_breakpoint;
  or1k_target.to_insert_watchpoint           = or1k_insert_watchpoint;
  or1k_target.to_insert_watchpoint           = or1k_insert_watchpoint;
  or1k_target.to_remove_watchpoint           = or1k_remove_watchpoint;
  or1k_target.to_remove_watchpoint           = or1k_remove_watchpoint;
  or1k_target.to_stopped_by_watchpoint       = or1k_stopped_by_watchpoint;
  or1k_target.to_stopped_by_watchpoint       = or1k_stopped_by_watchpoint;
  or1k_target.to_stopped_data_address        = or1k_stopped_data_address;
  or1k_target.to_stopped_data_address        = or1k_stopped_data_address;
  or1k_target.to_region_ok_for_hw_watchpoint = or1k_region_ok_for_hw_watchpoint;
  or1k_target.to_region_ok_for_hw_watchpoint = or1k_region_ok_for_hw_watchpoint;
 
 
  or1k_target.to_resume                      = or1k_resume;
  or1k_target.to_resume                      = or1k_resume;
  or1k_target.to_wait                        = or1k_wait;
  or1k_target.to_wait                        = or1k_wait;
  or1k_target.to_stop                        = or1k_stop;
  or1k_target.to_stop                        = or1k_stop;
  or1k_target.to_kill                        = or1k_kill;
  or1k_target.to_kill                        = or1k_kill;
  or1k_target.to_create_inferior             = or1k_create_inferior;
  or1k_target.to_create_inferior             = or1k_create_inferior;
  or1k_target.to_mourn_inferior              = or1k_mourn_inferior;
  or1k_target.to_mourn_inferior              = or1k_mourn_inferior;
 
 
  or1k_target.to_rcmd                        = or1k_rcmd;
  or1k_target.to_rcmd                        = or1k_rcmd;
 
 
  or1k_target.to_magic                       = OPS_MAGIC;
  or1k_target.to_magic                       = OPS_MAGIC;
 
 
  /* Tell GDB about the new target */
  /* Tell GDB about the new target */
 
 
  add_target (&or1k_target);
  add_target (&or1k_target);
 
 
}       /* _initialize_remote_or1k() */
}       /* _initialize_remote_or1k() */
 
 
 
 
/* EOF */
/* EOF */
 
 

powered by: WebSVN 2.1.0

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