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

Subversion Repositories adv_debug_sys

[/] [adv_debug_sys/] [trunk/] [Software/] [adv_jtag_bridge/] [rsp-server.c] - Diff between revs 8 and 14

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

Rev 8 Rev 14
/* rsp-server.c -- Remote Serial Protocol server for GDB
/* rsp-server.c -- Remote Serial Protocol server for GDB
 
 
Copyright (C) 2008 Embecosm Limited
Copyright (C) 2008 Embecosm Limited
 
 
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
 
This file was part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
This file was part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
Adapted for adv_jtag_bridge by Nathan Yawn <nyawn@opencores.org>
Adapted for adv_jtag_bridge by Nathan Yawn <nyawn@opencores.org>
 
 
This program is free software; you can redistribute it and/or modify it
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option)
Software Foundation; either version 3 of the License, or (at your option)
any later version.
any later version.
 
 
This program is distributed in the hope that it will be useful, but WITHOUT
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
more details.
more details.
 
 
You should have received a copy of the GNU General Public License along
You should have received a copy of the GNU General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
*/
 
 
/* This program is commented throughout in a fashion suitable for processing
/* This program is commented throughout in a fashion suitable for processing
   with Doxygen. */
   with Doxygen. */
 
 
/* System includes */
/* System includes */
#include <stdlib.h>
#include <stdlib.h>
#include <unistd.h>
#include <unistd.h>
#include <netdb.h>
#include <netdb.h>
#include <stdio.h>
#include <stdio.h>
#include <errno.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <arpa/inet.h>
#include <poll.h>
#include <poll.h>
#include <netinet/tcp.h>
#include <netinet/tcp.h>
#include <string.h>
#include <string.h>
#include <pthread.h>
#include <pthread.h>
 
 
/* Package includes */
/* Package includes */
#include "except.h"
#include "except.h"
#include "spr-defs.h"
#include "spr-defs.h"
#include "chain_commands.h"
#include "dbg_api.h"
#include "errcodes.h"
#include "errcodes.h"
 
 
/* Define to log each packet */
/* Define to log each packet */
#define RSP_TRACE  0
#define RSP_TRACE  0
 
 
/*! Name of the RSP service */
/*! Name of the RSP service */
#define OR1KSIM_RSP_SERVICE  "jtag-rsp"
#define OR1KSIM_RSP_SERVICE  "jtag-rsp"
 
 
/*! Protocol used by Or1ksim */
/*! Protocol used by Or1ksim */
#define OR1KSIM_RSP_PROTOCOL  "tcp"
#define OR1KSIM_RSP_PROTOCOL  "tcp"
 
 
/* Indices of GDB registers that are not GPRs. Must match GDB settings! */
/* Indices of GDB registers that are not GPRs. Must match GDB settings! */
#define PPC_REGNUM  (MAX_GPRS + 0)      /*!< Previous PC */
#define PPC_REGNUM  (MAX_GPRS + 0)      /*!< Previous PC */
#define NPC_REGNUM  (MAX_GPRS + 1)      /*!< Next PC */
#define NPC_REGNUM  (MAX_GPRS + 1)      /*!< Next PC */
#define SR_REGNUM   (MAX_GPRS + 2)      /*!< Supervision Register */
#define SR_REGNUM   (MAX_GPRS + 2)      /*!< Supervision Register */
#define NUM_REGS    (MAX_GRPS + 3)      /*!< Total GDB registers */
#define NUM_REGS    (MAX_GRPS + 3)      /*!< Total GDB registers */
 
 
/*! Trap instruction for OR32 */
/*! Trap instruction for OR32 */
#define OR1K_TRAP_INSTR  0x21000001
#define OR1K_TRAP_INSTR  0x21000001
 
 
/*! Definition of GDB target signals. Data taken from the GDB 6.8
/*! Definition of GDB target signals. Data taken from the GDB 6.8
    source. Only those we use defined here. */
    source. Only those we use defined here. */
enum target_signal {
enum target_signal {
  TARGET_SIGNAL_NONE =  0,
  TARGET_SIGNAL_NONE =  0,
  TARGET_SIGNAL_INT  =  2,
  TARGET_SIGNAL_INT  =  2,
  TARGET_SIGNAL_ILL  =  4,
  TARGET_SIGNAL_ILL  =  4,
  TARGET_SIGNAL_TRAP =  5,
  TARGET_SIGNAL_TRAP =  5,
  TARGET_SIGNAL_FPE  =  8,
  TARGET_SIGNAL_FPE  =  8,
  TARGET_SIGNAL_BUS  = 10,
  TARGET_SIGNAL_BUS  = 10,
  TARGET_SIGNAL_SEGV = 11,
  TARGET_SIGNAL_SEGV = 11,
  TARGET_SIGNAL_ALRM = 14,
  TARGET_SIGNAL_ALRM = 14,
  TARGET_SIGNAL_USR2 = 31,
  TARGET_SIGNAL_USR2 = 31,
  TARGET_SIGNAL_PWR  = 32
  TARGET_SIGNAL_PWR  = 32
};
};
 
 
/*! The maximum number of characters in inbound/outbound buffers.  The largest
/*! The maximum number of characters in inbound/outbound buffers.  The largest
    packets are the 'G' packet, which must hold the 'G' and all the registers
    packets are the 'G' packet, which must hold the 'G' and all the registers
    with two hex digits per byte and the 'g' reply, which must hold all the
    with two hex digits per byte and the 'g' reply, which must hold all the
    registers, and (in our implementation) an end-of-string (0)
    registers, and (in our implementation) an end-of-string (0)
    character. Adding the EOS allows us to print out the packet as a
    character. Adding the EOS allows us to print out the packet as a
    string. So at least NUMREGBYTES*2 + 1 (for the 'G' or the EOS) are needed
    string. So at least NUMREGBYTES*2 + 1 (for the 'G' or the EOS) are needed
    for register packets */
    for register packets */
#define GDB_BUF_MAX  ((NUM_REGS) * 8 + 1)
#define GDB_BUF_MAX  ((NUM_REGS) * 8 + 1)
 
 
/*! Size of the matchpoint hash table. Largest prime < 2^10 */
/*! Size of the matchpoint hash table. Largest prime < 2^10 */
#define MP_HASH_SIZE  1021
#define MP_HASH_SIZE  1021
 
 
/*! String to map hex digits to chars */
/*! String to map hex digits to chars */
static const char hexchars[]="0123456789abcdef";
static const char hexchars[]="0123456789abcdef";
 
 
/*! Data structure for RSP buffers. Can't be null terminated, since it may
/*! Data structure for RSP buffers. Can't be null terminated, since it may
  include zero bytes */
  include zero bytes */
struct rsp_buf
struct rsp_buf
{
{
  char  data[GDB_BUF_MAX];
  char  data[GDB_BUF_MAX];
  int   len;
  int   len;
};
};
 
 
/*! Enumeration of different types of matchpoint. These have explicit values
/*! Enumeration of different types of matchpoint. These have explicit values
    matching the second digit of 'z' and 'Z' packets. */
    matching the second digit of 'z' and 'Z' packets. */
enum mp_type {
enum mp_type {
  BP_MEMORY   = 0,
  BP_MEMORY   = 0,
  BP_HARDWARE = 1,
  BP_HARDWARE = 1,
  WP_WRITE    = 2,
  WP_WRITE    = 2,
  WP_READ     = 3,
  WP_READ     = 3,
  WP_ACCESS   = 4
  WP_ACCESS   = 4
};
};
 
 
/*! Data structure for a matchpoint hash table entry */
/*! Data structure for a matchpoint hash table entry */
struct mp_entry
struct mp_entry
{
{
  enum mp_type       type;              /*!< Type of matchpoint */
  enum mp_type       type;              /*!< Type of matchpoint */
  unsigned long int  addr;              /*!< Address with the matchpoint */
  unsigned long int  addr;              /*!< Address with the matchpoint */
  unsigned long int  instr;             /*!< Substituted instruction */
  unsigned long int  instr;             /*!< Substituted instruction */
  struct mp_entry   *next;              /*!< Next entry with this hash */
  struct mp_entry   *next;              /*!< Next entry with this hash */
};
};
 
 
/* Data to interface the GDB handler thread with the target handler thread */
/* Data to interface the GDB handler thread with the target handler thread */
pthread_mutex_t rsp_mutex = PTHREAD_MUTEX_INITIALIZER;  /*!< Mutex to protect the "target_running" member of the rsp struct */
pthread_mutex_t rsp_mutex = PTHREAD_MUTEX_INITIALIZER;  /*!< Mutex to protect the "target_running" member of the rsp struct */
pthread_mutex_t target_handler_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t target_handler_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t target_handler_cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t target_handler_cond = PTHREAD_COND_INITIALIZER;
 
 
int target_handler_state = 0;
int target_handler_state = 0;
pthread_t target_handler_thread;
pthread_t target_handler_thread;
void *target_handler(void *arg);
void *target_handler(void *arg);
 
 
int pipe_fds[2];  // Descriptors for the pipe from the poller thread to the GDB interface thread
int pipe_fds[2];  // Descriptors for the pipe from the poller thread to the GDB interface thread
 
 
// Work-around for the current OR1200 implementation; After setting the NPC,
// Work-around for the current OR1200 implementation; After setting the NPC,
// it always reads back 0 until the next instruction is executed.  This
// it always reads back 0 until the next instruction is executed.  This
// is a problem with the way we handle memory breakpoints (resetting the NPC),
// is a problem with the way we handle memory breakpoints (resetting the NPC),
// so we cache the last value we set the NPC to, incase we need it.
// so we cache the last value we set the NPC to, incase we need it.
unsigned char use_cached_npc = 0;
unsigned char use_cached_npc = 0;
unsigned int cached_npc = 0;
unsigned int cached_npc = 0;
 
 
/*! Central data for the RSP connection */
/*! Central data for the RSP connection */
static struct
static struct
{
{
  int                client_waiting;    /*!< Is client waiting a response? */
  int                client_waiting;    /*!< Is client waiting a response? */
  int                target_running;    /*!< Is target hardware running? --NAY */
  int                target_running;    /*!< Is target hardware running? --NAY */
  int                single_step_mode;
  int                single_step_mode;
  int                proto_num;         /*!< Number of the protocol used */
  int                proto_num;         /*!< Number of the protocol used */
  int                server_fd;         /*!< FD for new connections */
  int                server_fd;         /*!< FD for new connections */
  int                client_fd;         /*!< FD for talking to GDB */
  int                client_fd;         /*!< FD for talking to GDB */
  int                sigval;            /*!< GDB signal for any exception */
  int                sigval;            /*!< GDB signal for any exception */
  unsigned long int  start_addr;        /*!< Start of last run */
  unsigned long int  start_addr;        /*!< Start of last run */
  struct mp_entry   *mp_hash[MP_HASH_SIZE];     /*!< Matchpoint hash table */
  struct mp_entry   *mp_hash[MP_HASH_SIZE];     /*!< Matchpoint hash table */
} rsp;
} rsp;
 
 
/* Forward declarations of static functions */
/* Forward declarations of static functions */
void  rsp_exception (unsigned long int except);
void  rsp_exception (unsigned long int except);
static void               rsp_server_request ();
static void               rsp_server_request ();
static void               rsp_client_request ();
static void               rsp_client_request ();
static void               rsp_server_close ();
static void               rsp_server_close ();
static void               rsp_client_close ();
static void               rsp_client_close ();
static void               put_packet (struct rsp_buf *buf);
static void               put_packet (struct rsp_buf *buf);
static void               put_str_packet (const char *str);
static void               put_str_packet (const char *str);
static struct rsp_buf    *get_packet ();
static struct rsp_buf    *get_packet ();
static void               put_rsp_char (char  c);
static void               put_rsp_char (char  c);
static int                get_rsp_char ();
static int                get_rsp_char ();
static int                rsp_unescape (char *data,
static int                rsp_unescape (char *data,
                                        int   len);
                                        int   len);
static void               mp_hash_init ();
static void               mp_hash_init ();
static void               mp_hash_add (enum mp_type       type,
static void               mp_hash_add (enum mp_type       type,
                                       unsigned long int  addr,
                                       unsigned long int  addr,
                                       unsigned long int  instr);
                                       unsigned long int  instr);
static struct mp_entry   *mp_hash_lookup (enum mp_type       type,
static struct mp_entry   *mp_hash_lookup (enum mp_type       type,
                                          unsigned long int  addr);
                                          unsigned long int  addr);
static struct mp_entry   *mp_hash_delete (enum mp_type       type,
static struct mp_entry   *mp_hash_delete (enum mp_type       type,
                                          unsigned long int  addr);
                                          unsigned long int  addr);
static int                hex (int  c);
static int                hex (int  c);
static void               reg2hex (unsigned long int  val,
static void               reg2hex (unsigned long int  val,
                                   char              *buf);
                                   char              *buf);
static unsigned long int  hex2reg (char *buf);
static unsigned long int  hex2reg (char *buf);
static void               ascii2hex (char *dest,
static void               ascii2hex (char *dest,
                                     char *src);
                                     char *src);
static void               hex2ascii (char *dest,
static void               hex2ascii (char *dest,
                                     char *src);
                                     char *src);
static unsigned int       set_npc (unsigned long int  addr);
static unsigned int       set_npc (unsigned long int  addr);
static void               rsp_report_exception ();
static void               rsp_report_exception ();
static void               rsp_continue (struct rsp_buf *buf);
static void               rsp_continue (struct rsp_buf *buf);
static void               rsp_continue_with_signal (struct rsp_buf *buf);
static void               rsp_continue_with_signal (struct rsp_buf *buf);
static void               rsp_continue_generic (unsigned long int  except);
static void               rsp_continue_generic (unsigned long int  except);
static void               rsp_read_all_regs ();
static void               rsp_read_all_regs ();
static void               rsp_write_all_regs (struct rsp_buf *buf);
static void               rsp_write_all_regs (struct rsp_buf *buf);
static void               rsp_read_mem (struct rsp_buf *buf);
static void               rsp_read_mem (struct rsp_buf *buf);
static void               rsp_write_mem (struct rsp_buf *buf);
static void               rsp_write_mem (struct rsp_buf *buf);
static void               rsp_read_reg (struct rsp_buf *buf);
static void               rsp_read_reg (struct rsp_buf *buf);
static void               rsp_write_reg (struct rsp_buf *buf);
static void               rsp_write_reg (struct rsp_buf *buf);
static void               rsp_query (struct rsp_buf *buf);
static void               rsp_query (struct rsp_buf *buf);
static void               rsp_command (struct rsp_buf *buf);
static void               rsp_command (struct rsp_buf *buf);
static void               rsp_set (struct rsp_buf *buf);
static void               rsp_set (struct rsp_buf *buf);
static void               rsp_restart ();
static void               rsp_restart ();
static void               rsp_step (struct rsp_buf *buf);
static void               rsp_step (struct rsp_buf *buf);
static void               rsp_step_with_signal (struct rsp_buf *buf);
static void               rsp_step_with_signal (struct rsp_buf *buf);
static void               rsp_step_generic (unsigned long int  except);
static void               rsp_step_generic (unsigned long int  except);
static void               rsp_vpkt (struct rsp_buf *buf);
static void               rsp_vpkt (struct rsp_buf *buf);
static void               rsp_write_mem_bin (struct rsp_buf *buf);
static void               rsp_write_mem_bin (struct rsp_buf *buf);
static void               rsp_remove_matchpoint (struct rsp_buf *buf);
static void               rsp_remove_matchpoint (struct rsp_buf *buf);
static void               rsp_insert_matchpoint (struct rsp_buf *buf);
static void               rsp_insert_matchpoint (struct rsp_buf *buf);
 
 
void set_stall_state(int stall);
void set_stall_state(int stall);
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Initialize the Remote Serial Protocol connection
/*!Initialize the Remote Serial Protocol connection
 
 
   This involves setting up a socket to listen on a socket for attempted
   This involves setting up a socket to listen on a socket for attempted
   connections from a single GDB instance (we couldn't be talking to multiple
   connections from a single GDB instance (we couldn't be talking to multiple
   GDBs at once!).
   GDBs at once!).
 
 
   The service is specified either as a port number in the Or1ksim configuration
   The service is specified either as a port number in the Or1ksim configuration
   (parameter rsp_port in section debug, default 51000) or as a service name
   (parameter rsp_port in section debug, default 51000) or as a service name
   in the constant OR1KSIM_RSP_SERVICE.
   in the constant OR1KSIM_RSP_SERVICE.
 
 
   The protocol used for communication is specified in OR1KSIM_RSP_PROTOCOL. */
   The protocol used for communication is specified in OR1KSIM_RSP_PROTOCOL. */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
void
void
rsp_init (int portNum)
rsp_init (int portNum)
{
{
  struct protoent    *protocol;         /* Protocol number */
  struct protoent    *protocol;         /* Protocol number */
  struct hostent     *host_entry;       /* Our host entry */
  struct hostent     *host_entry;       /* Our host entry */
  struct sockaddr_in  sock_addr;        /* Socket address */
  struct sockaddr_in  sock_addr;        /* Socket address */
 
 
  int                 optval;           /* Socket options */
  int                 optval;           /* Socket options */
  int                 flags;            /* Socket flags */
  int                 flags;            /* Socket flags */
  char                name[256];        /* Our name */
  char                name[256];        /* Our name */
  unsigned long       tmp;
  unsigned long       tmp;
 
 
 
 
  /* Clear out the central data structure */
  /* Clear out the central data structure */
  rsp.client_waiting =  0;               /* GDB client is not waiting for us */
  rsp.client_waiting =  0;               /* GDB client is not waiting for us */
  rsp.proto_num      = -1;              /* i.e. invalid */
  rsp.proto_num      = -1;              /* i.e. invalid */
  rsp.server_fd      = -1;              /* i.e. invalid */
  rsp.server_fd      = -1;              /* i.e. invalid */
  rsp.client_fd      = -1;              /* i.e. invalid */
  rsp.client_fd      = -1;              /* i.e. invalid */
  rsp.sigval         =  0;               /* No exception */
  rsp.sigval         =  0;               /* No exception */
  rsp.start_addr     = EXCEPT_RESET;    /* Default restart point */
  rsp.start_addr     = EXCEPT_RESET;    /* Default restart point */
 
 
  /* Set up the matchpoint hash table */
  /* Set up the matchpoint hash table */
  mp_hash_init ();
  mp_hash_init ();
 
 
  /* Get the protocol number of TCP and save it for future use */
  /* Get the protocol number of TCP and save it for future use */
  protocol = getprotobyname (OR1KSIM_RSP_PROTOCOL);
  protocol = getprotobyname (OR1KSIM_RSP_PROTOCOL);
  if (NULL == protocol)
  if (NULL == protocol)
    {
    {
      fprintf (stderr, "Warning: RSP unable to load protocol \"%s\": %s\n",
      fprintf (stderr, "Warning: RSP unable to load protocol \"%s\": %s\n",
               OR1KSIM_RSP_PROTOCOL, strerror (errno));
               OR1KSIM_RSP_PROTOCOL, strerror (errno));
      return;
      return;
    }
    }
 
 
  rsp.proto_num = protocol->p_proto;    /* Saved for future client use */
  rsp.proto_num = protocol->p_proto;    /* Saved for future client use */
 
 
  /* 0 is used as the RSP port number to indicate that we should use the
  /* 0 is used as the RSP port number to indicate that we should use the
     service name instead. */
     service name instead. */
  if (0 == portNum)
  if (0 == portNum)
    {
    {
      struct servent *service =
      struct servent *service =
        getservbyname (OR1KSIM_RSP_SERVICE, protocol->p_name);
        getservbyname (OR1KSIM_RSP_SERVICE, protocol->p_name);
 
 
      if (NULL == service)
      if (NULL == service)
        {
        {
          fprintf (stderr, "Warning: RSP unable to find service \"%s\": %s\n",
          fprintf (stderr, "Warning: RSP unable to find service \"%s\": %s\n",
                   OR1KSIM_RSP_SERVICE, strerror (errno));
                   OR1KSIM_RSP_SERVICE, strerror (errno));
          return;
          return;
        }
        }
 
 
      portNum = ntohs (service->s_port);
      portNum = ntohs (service->s_port);
    }
    }
 
 
  /* Create the socket using the TCP protocol */
  /* Create the socket using the TCP protocol */
  rsp.server_fd = socket (PF_INET, SOCK_STREAM, protocol->p_proto);
  rsp.server_fd = socket (PF_INET, SOCK_STREAM, protocol->p_proto);
  if (rsp.server_fd < 0)
  if (rsp.server_fd < 0)
    {
    {
      fprintf (stderr, "Warning: RSP could not create server socket: %s\n",
      fprintf (stderr, "Warning: RSP could not create server socket: %s\n",
               strerror (errno));
               strerror (errno));
      return;
      return;
    }
    }
 
 
  /* Set this socket to reuse its address. This allows the server to keep
  /* Set this socket to reuse its address. This allows the server to keep
     trying before a GDB session has got going. */
     trying before a GDB session has got going. */
  optval = 1;
  optval = 1;
  if (setsockopt(rsp.server_fd, SOL_SOCKET,
  if (setsockopt(rsp.server_fd, SOL_SOCKET,
                 SO_REUSEADDR, &optval, sizeof (optval)) < 0)
                 SO_REUSEADDR, &optval, sizeof (optval)) < 0)
    {
    {
      fprintf (stderr, "Cannot set SO_REUSEADDR option on server socket %d: "
      fprintf (stderr, "Cannot set SO_REUSEADDR option on server socket %d: "
               "%s\n", rsp.server_fd, strerror (errno));
               "%s\n", rsp.server_fd, strerror (errno));
      rsp_server_close();
      rsp_server_close();
      return;
      return;
    }
    }
 
 
  /* The server should be non-blocking. Get the current flags and then set the
  /* The server should be non-blocking. Get the current flags and then set the
     non-blocking flags */
     non-blocking flags */
  flags = fcntl (rsp.server_fd, F_GETFL);
  flags = fcntl (rsp.server_fd, F_GETFL);
  if (flags < 0)
  if (flags < 0)
    {
    {
      fprintf (stderr, "Warning: Unable to get flags for RSP server socket "
      fprintf (stderr, "Warning: Unable to get flags for RSP server socket "
               "%d: %s\n", rsp.server_fd, strerror (errno));
               "%d: %s\n", rsp.server_fd, strerror (errno));
      rsp_server_close();
      rsp_server_close();
      return;
      return;
    }
    }
 
 
  flags |= O_NONBLOCK;
  flags |= O_NONBLOCK;
  if (fcntl (rsp.server_fd, F_SETFL, flags) < 0)
  if (fcntl (rsp.server_fd, F_SETFL, flags) < 0)
    {
    {
      fprintf (stderr, "Warning: Unable to set flags for RSP server socket "
      fprintf (stderr, "Warning: Unable to set flags for RSP server socket "
               "%d to 0x%08x: %s\n", rsp.server_fd, flags, strerror (errno));
               "%d to 0x%08x: %s\n", rsp.server_fd, flags, strerror (errno));
      rsp_server_close();
      rsp_server_close();
      return;
      return;
    }
    }
 
 
  /* Find out what our name is */
  /* Find out what our name is */
  if (gethostname (name, sizeof (name)) < 0)
  if (gethostname (name, sizeof (name)) < 0)
    {
    {
      fprintf (stderr, "Warning: Unable to get hostname for RSP server: %s\n",
      fprintf (stderr, "Warning: Unable to get hostname for RSP server: %s\n",
               strerror (errno));
               strerror (errno));
      rsp_server_close();
      rsp_server_close();
      return;
      return;
    }
    }
 
 
  /* Find out what our address is */
  /* Find out what our address is */
  host_entry = gethostbyname (name);
  host_entry = gethostbyname (name);
  if (NULL == host_entry)
  if (NULL == host_entry)
    {
    {
      fprintf (stderr, "Warning: Unable to get host entry for RSP server: "
      fprintf (stderr, "Warning: Unable to get host entry for RSP server: "
               "%s\n", strerror (errno));
               "%s\n", strerror (errno));
      rsp_server_close();
      rsp_server_close();
      return;
      return;
    }
    }
 
 
  /* Bind our socket to the appropriate address */
  /* Bind our socket to the appropriate address */
  memset (&sock_addr, 0, sizeof (sock_addr));
  memset (&sock_addr, 0, sizeof (sock_addr));
  sock_addr.sin_family = host_entry->h_addrtype;
  sock_addr.sin_family = host_entry->h_addrtype;
  sock_addr.sin_port   = htons (portNum);
  sock_addr.sin_port   = htons (portNum);
 
 
  if (bind (rsp.server_fd,
  if (bind (rsp.server_fd,
            (struct sockaddr *)&sock_addr, sizeof (sock_addr)) < 0)
            (struct sockaddr *)&sock_addr, sizeof (sock_addr)) < 0)
    {
    {
      fprintf (stderr, "Warning: Unable to bind RSP server socket %d to port "
      fprintf (stderr, "Warning: Unable to bind RSP server socket %d to port "
               "%d: %s\n", rsp.server_fd, portNum,
               "%d: %s\n", rsp.server_fd, portNum,
               strerror (errno));
               strerror (errno));
      rsp_server_close();
      rsp_server_close();
      return;
      return;
    }
    }
 
 
  /* Mark us as a passive port, with a maximum backlog of 1 connection (we
  /* Mark us as a passive port, with a maximum backlog of 1 connection (we
     never connect simultaneously to more than one RSP client!) */
     never connect simultaneously to more than one RSP client!) */
  if (listen (rsp.server_fd, 1) < 0)
  if (listen (rsp.server_fd, 1) < 0)
    {
    {
      fprintf (stderr, "Warning: Unable to set RSP backlog on server socket "
      fprintf (stderr, "Warning: Unable to set RSP backlog on server socket "
               "%d to %d: %s\n", rsp.server_fd, 1, strerror (errno));
               "%d to %d: %s\n", rsp.server_fd, 1, strerror (errno));
      rsp_server_close();
      rsp_server_close();
      return;
      return;
    }
    }
 
 
  // Stall the CPU...it starts off running.
  // Stall the CPU...it starts off running.
  set_stall_state(1);
  set_stall_state(1);
  rsp.target_running = 0;
  rsp.target_running = 0;
  target_handler_state = 0;  // Don't start the polling thread until we have a client
  target_handler_state = 0;  // Don't start the polling thread until we have a client
  rsp.single_step_mode = 0;
  rsp.single_step_mode = 0;
 
 
  // Set up the CPU to break to the debug unit on exceptions.
  // Set up the CPU to break to the debug unit on exceptions.
  dbg_cpu0_read(SPR_DSR, &tmp);
  dbg_cpu0_read(SPR_DSR, &tmp);
  dbg_cpu0_write(SPR_DSR, tmp|SPR_DSR_TE|SPR_DSR_FPE|SPR_DSR_RE|SPR_DSR_IIE|SPR_DSR_AE|SPR_DSR_BUSEE);
  dbg_cpu0_write(SPR_DSR, tmp|SPR_DSR_TE|SPR_DSR_FPE|SPR_DSR_RE|SPR_DSR_IIE|SPR_DSR_AE|SPR_DSR_BUSEE);
 
 
  // Enable TRAP exception, but don't otherwise change the SR
  // Enable TRAP exception, but don't otherwise change the SR
  dbg_cpu0_read(SPR_SR, &tmp);
  dbg_cpu0_read(SPR_SR, &tmp);
  dbg_cpu0_write(SPR_SR, tmp|SPR_SR_SM);  // We set 'supervisor mode', which also enables TRAP exceptions
  dbg_cpu0_write(SPR_SR, tmp|SPR_SR_SM);  // We set 'supervisor mode', which also enables TRAP exceptions
 
 
  if(0 > pipe(pipe_fds)) {  // pipe_fds[0] is for reading, [1] is for writing
  if(0 > pipe(pipe_fds)) {  // pipe_fds[0] is for reading, [1] is for writing
    perror("Error creating sockets: ");
    perror("Error creating sockets: ");
    rsp_server_close();
    rsp_server_close();
    return;
    return;
  }
  }
 
 
  // Create the harware target polling thread
  // Create the harware target polling thread
  if(pthread_create(&target_handler_thread, NULL, target_handler, NULL))
  if(pthread_create(&target_handler_thread, NULL, target_handler, NULL))
    {
    {
      fprintf(stderr, "Failed to create target handler thread!\n");
      fprintf(stderr, "Failed to create target handler thread!\n");
      rsp_server_close();
      rsp_server_close();
      return;
      return;
    }
    }
 
 
}       /* rsp_init () */
}       /* rsp_init () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Look for action on RSP
/*!Look for action on RSP
 
 
   This function is called when the processor has stalled, which, except for
   This function is called when the processor has stalled, which, except for
   initialization, must be due to an interrupt.
   initialization, must be due to an interrupt.
 
 
   If we have no RSP client, we poll the RSP server for a client requesting to
   If we have no RSP client, we poll the RSP server for a client requesting to
   join. We can make no progress until the client is available.
   join. We can make no progress until the client is available.
 
 
   Then if the cause is an interrupt, and the interrupt not been notified to
   Then if the cause is an interrupt, and the interrupt not been notified to
   GDB, a packet reporting the cause of the interrupt is sent.
   GDB, a packet reporting the cause of the interrupt is sent.
 
 
   The function then polls the RSP client port (if open)
   The function then polls the RSP client port (if open)
   for available input. It then processes the GDB RSP request and return.
   for available input. It then processes the GDB RSP request and return.
 
 
   If an error occurs when polling the RSP server, other than an interrupt, a
   If an error occurs when polling the RSP server, other than an interrupt, a
   warning message is printed out and the RSP server and client (if open)
   warning message is printed out and the RSP server and client (if open)
   connections are closed.
   connections are closed.
 
 
   If an error occurs when polling the RSP client, other than an interrupt, a
   If an error occurs when polling the RSP client, other than an interrupt, a
   warning message is printed out and the RSP client connection is closed.
   warning message is printed out and the RSP client connection is closed.
 
 
   Polling is always blocking (i.e. timeout -1).                             */
   Polling is always blocking (i.e. timeout -1).                             */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
int handle_rsp (void)
int handle_rsp (void)
{
{
  struct pollfd  fds[2];        /* The FD to poll for */
  struct pollfd  fds[2];        /* The FD to poll for */
  char bitbucket;
  char bitbucket;
 
 
  /* Give up if no RSP server port (this should not occur) */
  /* Give up if no RSP server port (this should not occur) */
  if (-1 == rsp.server_fd)
  if (-1 == rsp.server_fd)
    {
    {
      fprintf (stderr, "Warning: No RSP server port open\n");
      fprintf (stderr, "Warning: No RSP server port open\n");
      return 0;
      return 0;
    }
    }
 
 
  /* If we have no RSP client, poll the server until we get one. */
  /* If we have no RSP client, poll the server until we get one. */
  while (-1 == rsp.client_fd)
  while (-1 == rsp.client_fd)
    {
    {
      /* Poll for a client on the RSP server socket */
      /* Poll for a client on the RSP server socket */
      fds[0].fd     = rsp.server_fd;     /* FD for the server socket */
      fds[0].fd     = rsp.server_fd;     /* FD for the server socket */
      fds[0].events = POLLIN;            /* Poll for input activity */
      fds[0].events = POLLIN;            /* Poll for input activity */
 
 
      /* Poll is always blocking. We can't do anything more until something
      /* Poll is always blocking. We can't do anything more until something
         happens here. */
         happens here. */
      switch (poll (fds, 1, -1))
      switch (poll (fds, 1, -1))
        {
        {
        case -1:
        case -1:
          /* Error. Only one we ignore is an interrupt */
          /* Error. Only one we ignore is an interrupt */
          if (EINTR != errno)
          if (EINTR != errno)
            {
            {
              fprintf (stderr, "Warning: poll for RSP failed: closing "
              fprintf (stderr, "Warning: poll for RSP failed: closing "
                       "server connection: %s\n", strerror (errno));
                       "server connection: %s\n", strerror (errno));
              rsp_client_close();
              rsp_client_close();
              rsp_server_close();
              rsp_server_close();
              return 0;
              return 0;
            }
            }
          break;
          break;
 
 
        case 0:
        case 0:
          /* Timeout. This can't occur! */
          /* Timeout. This can't occur! */
          fprintf (stderr, "Warning: Unexpected RSP server poll timeout\n");
          fprintf (stderr, "Warning: Unexpected RSP server poll timeout\n");
          break;
          break;
 
 
        default:
        default:
          /* Is the poll due to input available? If we succeed ignore any
          /* Is the poll due to input available? If we succeed ignore any
             outstanding reports of exceptions. */
             outstanding reports of exceptions. */
          if (POLLIN == (fds[0].revents & POLLIN))
          if (POLLIN == (fds[0].revents & POLLIN))
            {
            {
              rsp_server_request ();
              rsp_server_request ();
              rsp.client_waiting = 0;            /* No longer waiting */
              rsp.client_waiting = 0;            /* No longer waiting */
            }
            }
          else
          else
            {
            {
              /* Error leads to closing the client and server */
              /* Error leads to closing the client and server */
              fprintf (stderr, "Warning: RSP server received flags "
              fprintf (stderr, "Warning: RSP server received flags "
                       "0x%08x: closing server connection\n", fds[0].revents);
                       "0x%08x: closing server connection\n", fds[0].revents);
              rsp_client_close();
              rsp_client_close();
              rsp_server_close();
              rsp_server_close();
              return 0;
              return 0;
            }
            }
        }
        }
    }
    }
 
 
 
 
  /* Poll the RSP client socket for a message from GDB */
  /* Poll the RSP client socket for a message from GDB */
  /* Also watch for a message from the hardware poller thread.
  /* Also watch for a message from the hardware poller thread.
     This might be easier if we used ppoll() and sent a Signal, instead
     This might be easier if we used ppoll() and sent a Signal, instead
     of using a pipe?  */
     of using a pipe?  */
 
 
  fds[0].fd     = rsp.client_fd; /* FD for the client socket */
  fds[0].fd     = rsp.client_fd; /* FD for the client socket */
  fds[0].events = POLLIN;                /* Poll for input activity */
  fds[0].events = POLLIN;                /* Poll for input activity */
 
 
  fds[1].fd = pipe_fds[0];
  fds[1].fd = pipe_fds[0];
  fds[1].events = POLLIN;
  fds[1].events = POLLIN;
 
 
  /* Poll is always blocking. We can't do anything more until something
  /* Poll is always blocking. We can't do anything more until something
     happens here. */
     happens here. */
  //fprintf(stderr, "Polling...\n");
  //fprintf(stderr, "Polling...\n");
  switch (poll (fds, 2, -1))
  switch (poll (fds, 2, -1))
    {
    {
    case -1:
    case -1:
      /* Error. Only one we ignore is an interrupt */
      /* Error. Only one we ignore is an interrupt */
      if (EINTR != errno)
      if (EINTR != errno)
        {
        {
          fprintf (stderr, "Warning: poll for RSP failed: closing "
          fprintf (stderr, "Warning: poll for RSP failed: closing "
                   "server connection: %s\n", strerror (errno));
                   "server connection: %s\n", strerror (errno));
          rsp_client_close();
          rsp_client_close();
          rsp_server_close();
          rsp_server_close();
          return 0;
          return 0;
        }
        }
 
 
      return 1;
      return 1;
 
 
    case 0:
    case 0:
      /* Timeout. This can't occur! */
      /* Timeout. This can't occur! */
      fprintf (stderr, "Warning: Unexpected RSP client poll timeout\n");
      fprintf (stderr, "Warning: Unexpected RSP client poll timeout\n");
      return 1;
      return 1;
 
 
    default:
    default:
      /* Is the client activity due to input available? */
      /* Is the client activity due to input available? */
      if (POLLIN == (fds[0].revents & POLLIN))
      if (POLLIN == (fds[0].revents & POLLIN))
        {
        {
          rsp_client_request ();
          rsp_client_request ();
        }
        }
      else if(POLLIN == (fds[1].revents & POLLIN))
      else if(POLLIN == (fds[1].revents & POLLIN))
        {
        {
          //fprintf(stderr, "Got pipe event from monitor thread\n");
          //fprintf(stderr, "Got pipe event from monitor thread\n");
          read(pipe_fds[0], &bitbucket, 1);  // Clear the byte out and discard
          bitbucket = read(pipe_fds[0], &bitbucket, 1);  // Clear the byte out and discard
          /* If we have an unacknowledged exception and a client is available, tell
          /* If we have an unacknowledged exception and a client is available, tell
             GDB. If this exception was a trap due to a memory breakpoint, then
             GDB. If this exception was a trap due to a memory breakpoint, then
             adjust the NPC. */
             adjust the NPC. */
          if (rsp.client_waiting)
          if (rsp.client_waiting)
            {
            {
              // Read the PPC
              // Read the PPC
              unsigned long ppcval;
              unsigned long ppcval;
              dbg_cpu0_read(SPR_PPC, &ppcval);
              dbg_cpu0_read(SPR_PPC, &ppcval);
 
 
              if ((TARGET_SIGNAL_TRAP == rsp.sigval) &&
              if ((TARGET_SIGNAL_TRAP == rsp.sigval) &&
                  (NULL != mp_hash_lookup (BP_MEMORY, ppcval)))  // We also get TRAP from a single-step, don't change npc unless it's really a BP
                  (NULL != mp_hash_lookup (BP_MEMORY, ppcval)))  // We also get TRAP from a single-step, don't change npc unless it's really a BP
                {
                {
                  set_npc (ppcval);
                  set_npc (ppcval);
                }
                }
 
 
              rsp_report_exception();
              rsp_report_exception();
              rsp.client_waiting = 0;            /* No longer waiting */
              rsp.client_waiting = 0;            /* No longer waiting */
            }
            }
        }
        }
      else
      else
        {
        {
          /* Error leads to closing the client, but not the server. */
          /* Error leads to closing the client, but not the server. */
          fprintf (stderr, "Warning: RSP client received flags "
          fprintf (stderr, "Warning: RSP client received flags "
                   "0x%08x: closing client connection\n", fds[0].revents);
                   "0x%08x: closing client connection\n", fds[0].revents);
          rsp_client_close();
          rsp_client_close();
        }
        }
    }
    }
 
 
  return 1;
  return 1;
}       /* handle_rsp () */
}       /* handle_rsp () */
 
 
 
 
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//!Note an exception for future processing
//!Note an exception for future processing
//
//
//   The simulator has encountered an exception. Record it here, so that a
//   The simulator has encountered an exception. Record it here, so that a
//   future call to handle_exception will report it back to the client. The
//   future call to handle_exception will report it back to the client. The
//   signal is supplied in Or1ksim form and recorded in GDB form.
//   signal is supplied in Or1ksim form and recorded in GDB form.
 
 
//   We flag up a warning if an exception is already pending, and ignore the
//   We flag up a warning if an exception is already pending, and ignore the
//   earlier exception.
//   earlier exception.
 
 
//   @param[in] except  The exception                          
//   @param[in] except  The exception                          
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
 
 
void rsp_exception (unsigned long int  except)
void rsp_exception (unsigned long int  except)
{
{
  int  sigval;                  // GDB signal equivalent to exception
  int  sigval;                  // GDB signal equivalent to exception
 
 
  switch (except)
  switch (except)
    {
    {
    case SPR_DRR_RSTE:    sigval = TARGET_SIGNAL_PWR;  break;
    case SPR_DRR_RSTE:    sigval = TARGET_SIGNAL_PWR;  break;
    case SPR_DRR_BUSEE:   sigval = TARGET_SIGNAL_BUS;  break;
    case SPR_DRR_BUSEE:   sigval = TARGET_SIGNAL_BUS;  break;
    case SPR_DRR_DPFE:      sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_DPFE:      sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_IPFE:      sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_IPFE:      sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_TTE:     sigval = TARGET_SIGNAL_ALRM; break;
    case SPR_DRR_TTE:     sigval = TARGET_SIGNAL_ALRM; break;
    case SPR_DRR_AE:    sigval = TARGET_SIGNAL_BUS;  break;
    case SPR_DRR_AE:    sigval = TARGET_SIGNAL_BUS;  break;
    case SPR_DRR_IIE:  sigval = TARGET_SIGNAL_ILL;  break;
    case SPR_DRR_IIE:  sigval = TARGET_SIGNAL_ILL;  break;
    case SPR_DRR_IE:      sigval = TARGET_SIGNAL_INT;  break;
    case SPR_DRR_IE:      sigval = TARGET_SIGNAL_INT;  break;
    case SPR_DRR_DME: sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_DME: sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_IME: sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_IME: sigval = TARGET_SIGNAL_SEGV; break;
    case SPR_DRR_RE:    sigval = TARGET_SIGNAL_FPE;  break;
    case SPR_DRR_RE:    sigval = TARGET_SIGNAL_FPE;  break;
    case SPR_DRR_SCE:  sigval = TARGET_SIGNAL_USR2; break;
    case SPR_DRR_SCE:  sigval = TARGET_SIGNAL_USR2; break;
    case SPR_DRR_FPE:      sigval = TARGET_SIGNAL_FPE;  break;
    case SPR_DRR_FPE:      sigval = TARGET_SIGNAL_FPE;  break;
    case SPR_DRR_TE:     sigval = TARGET_SIGNAL_TRAP; break;
    case SPR_DRR_TE:     sigval = TARGET_SIGNAL_TRAP; break;
 
 
    // In the current OR1200 hardware implementation, a single-step does not create a TRAP,
    // In the current OR1200 hardware implementation, a single-step does not create a TRAP,
    // the DSR reads back 0.  GDB expects a TRAP, so...
    // the DSR reads back 0.  GDB expects a TRAP, so...
    case 0:            sigval = TARGET_SIGNAL_TRAP; break;
    case 0:            sigval = TARGET_SIGNAL_TRAP; break;
 
 
    default:
    default:
      fprintf (stderr, "Warning: Unknown RSP exception %lu: Ignored\n", except);
      fprintf (stderr, "Warning: Unknown RSP exception %lu: Ignored\n", except);
      return;
      return;
    }
    }
 
 
  if ((0 != rsp.sigval) && (sigval != rsp.sigval))
  if ((0 != rsp.sigval) && (sigval != rsp.sigval))
    {
    {
      fprintf (stderr, "Warning: RSP signal %d received while signal "
      fprintf (stderr, "Warning: RSP signal %d received while signal "
               "%d pending: Pending exception replaced\n", sigval, rsp.sigval);
               "%d pending: Pending exception replaced\n", sigval, rsp.sigval);
    }
    }
 
 
  rsp.sigval         = sigval;          // Save the signal value
  rsp.sigval         = sigval;          // Save the signal value
 
 
} // rsp_exception () 
} // rsp_exception () 
 
 
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a request to the server for a new client
/*!Handle a request to the server for a new client
 
 
   We may already have a client. If we do, we will accept an immediately close
   We may already have a client. If we do, we will accept an immediately close
   the new client.                                                           */
   the new client.                                                           */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_server_request ()
rsp_server_request ()
{
{
  struct sockaddr_in  sock_addr;        /* The socket address */
  struct sockaddr_in  sock_addr;        /* The socket address */
  socklen_t           len;              /* Size of the socket address */
  socklen_t           len;              /* Size of the socket address */
  int                 fd;               /* The client FD */
  int                 fd;               /* The client FD */
  int                 flags;            /* fcntl () flags */
  int                 flags;            /* fcntl () flags */
  int                 optval;           /* Option value for setsockopt () */
  int                 optval;           /* Option value for setsockopt () */
 
 
  /* Get the client FD */
  /* Get the client FD */
  len = sizeof (sock_addr);
  len = sizeof (sock_addr);
  fd  = accept (rsp.server_fd, (struct sockaddr *)&sock_addr, &len);
  fd  = accept (rsp.server_fd, (struct sockaddr *)&sock_addr, &len);
  if (fd < 0)
  if (fd < 0)
    {
    {
      /* This is can happen, because a connection could have started, and then
      /* This is can happen, because a connection could have started, and then
         terminated due to a protocol error or user initiation before the
         terminated due to a protocol error or user initiation before the
         accept could take place.
         accept could take place.
 
 
         Two of the errors we can ignore (a retry is permissible). All other
         Two of the errors we can ignore (a retry is permissible). All other
         errors, we assume the server port has gone tits up and close. */
         errors, we assume the server port has gone tits up and close. */
 
 
      if ((errno != EWOULDBLOCK) && (errno != EAGAIN))
      if ((errno != EWOULDBLOCK) && (errno != EAGAIN))
        {
        {
          fprintf (stderr, "Warning: RSP server error creating client: "
          fprintf (stderr, "Warning: RSP server error creating client: "
                   "closing connection %s\n", strerror (errno));
                   "closing connection %s\n", strerror (errno));
          rsp_client_close ();
          rsp_client_close ();
          rsp_server_close ();
          rsp_server_close ();
        }
        }
 
 
      return;
      return;
    }
    }
 
 
  /* If we already have a client, then immediately close the new one */
  /* If we already have a client, then immediately close the new one */
  if (-1 != rsp.client_fd)
  if (-1 != rsp.client_fd)
    {
    {
      fprintf (stderr, "Warning: Additional RSP client request refused\n");
      fprintf (stderr, "Warning: Additional RSP client request refused\n");
      close (fd);
      close (fd);
      return;
      return;
    }
    }
 
 
  /* We have a new client, which should be non-blocking. Get the current flags
  /* We have a new client, which should be non-blocking. Get the current flags
     and then set the non-blocking flags */
     and then set the non-blocking flags */
  flags = fcntl (fd, F_GETFL);
  flags = fcntl (fd, F_GETFL);
  if (flags < 0)
  if (flags < 0)
    {
    {
      fprintf (stderr, "Warning: Unable to get flags for RSP client socket "
      fprintf (stderr, "Warning: Unable to get flags for RSP client socket "
               "%d: %s\n", fd, strerror (errno));
               "%d: %s\n", fd, strerror (errno));
      close (fd);
      close (fd);
      return;
      return;
    }
    }
 
 
  flags |= O_NONBLOCK;
  flags |= O_NONBLOCK;
  if (fcntl (fd, F_SETFL, flags) < 0)
  if (fcntl (fd, F_SETFL, flags) < 0)
    {
    {
      fprintf (stderr, "Warning: Unable to set flags for RSP client socket "
      fprintf (stderr, "Warning: Unable to set flags for RSP client socket "
               "%d to 0x%08x: %s\n", fd, flags, strerror (errno));
               "%d to 0x%08x: %s\n", fd, flags, strerror (errno));
      close (fd);
      close (fd);
      return;
      return;
    }
    }
 
 
  /* Turn of Nagel's algorithm for the client socket. This means the client
  /* Turn of Nagel's algorithm for the client socket. This means the client
     sends stuff immediately, it doesn't wait to fill up a packet. */
     sends stuff immediately, it doesn't wait to fill up a packet. */
  optval = 0;
  optval = 0;
  len    = sizeof (optval);
  len    = sizeof (optval);
  if (setsockopt (fd, rsp.proto_num, TCP_NODELAY, &optval, len) < 0)
  if (setsockopt (fd, rsp.proto_num, TCP_NODELAY, &optval, len) < 0)
    {
    {
      fprintf (stderr, "Warning: Unable to disable Nagel's algorithm for "
      fprintf (stderr, "Warning: Unable to disable Nagel's algorithm for "
               "RSP client socket %d: %s\n", fd, strerror (errno));
               "RSP client socket %d: %s\n", fd, strerror (errno));
      close (fd);
      close (fd);
      return;
      return;
    }
    }
 
 
  /* We have a new client socket */
  /* We have a new client socket */
  rsp.client_fd = fd;
  rsp.client_fd = fd;
 
 
  // Set the hardware polling thread to run
  // Set the hardware polling thread to run
  // This will cause the poll() to be interrupted next time
  // This will cause the poll() to be interrupted next time
  pthread_mutex_lock(&target_handler_mutex);
  pthread_mutex_lock(&target_handler_mutex);
  target_handler_state = 1;
  target_handler_state = 1;
  pthread_mutex_unlock(&target_handler_mutex);
  pthread_mutex_unlock(&target_handler_mutex);
 
 
}       /* rsp_server_request () */
}       /* rsp_server_request () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Deal with a request from the GDB client session
/*!Deal with a request from the GDB client session
 
 
   In general, apart from the simplest requests, this function replies on
   In general, apart from the simplest requests, this function replies on
   other functions to implement the functionality.                           */
   other functions to implement the functionality.                           */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_client_request ()
rsp_client_request ()
{
{
  struct rsp_buf *buf = get_packet ();  /* Message sent to us */
  struct rsp_buf *buf = get_packet ();  /* Message sent to us */
 
 
  // Null packet means we hit EOF or the link was closed for some other
  // Null packet means we hit EOF or the link was closed for some other
  // reason. Close the client and return
  // reason. Close the client and return
  if (NULL == buf)
  if (NULL == buf)
    {
    {
      rsp_client_close ();
      rsp_client_close ();
      return;
      return;
    }
    }
 
 
#if RSP_TRACE
#if RSP_TRACE
  printf ("Packet received %s: %d chars\n", buf->data, buf->len );
  printf ("Packet received %s: %d chars\n", buf->data, buf->len );
  fflush (stdout);
  fflush (stdout);
#endif
#endif
 
 
  // Check if target is running.
  // Check if target is running.
  int running = 0;
  int running = 0;
  pthread_mutex_lock(&rsp_mutex);
  pthread_mutex_lock(&rsp_mutex);
  running = rsp.target_running;
  running = rsp.target_running;
  pthread_mutex_unlock(&rsp_mutex);
  pthread_mutex_unlock(&rsp_mutex);
 
 
  // If running, only process async BREAK command
  // If running, only process async BREAK command
  if(running)
  if(running)
    {
    {
      if(buf->data[0] == 0x03)  // 0x03 is the ctrl-C "break" command from GDB
      if(buf->data[0] == 0x03)  // 0x03 is the ctrl-C "break" command from GDB
        {
        {
          // Send the STALL command to the target  
          // Send the STALL command to the target  
          set_stall_state (1);
          set_stall_state (1);
        }
        }
      else
      else
        {
        {
          // *** TODO Send a response to GDB indicating the target is not stalled?
          // Send a response to GDB indicating the target is not stalled: "Target not stopped"
          //put_str_packet("O");  // Need to hex-encode warning string
          put_str_packet("O6154677274656e20746f73206f74707064650a0d");  // Need to hex-encode warning string (I think...)
          fprintf(stderr, "WARNING:  Received GDB command 0x%X (%c) while target running!\n", buf->data[0], buf->data[0]);
          fprintf(stderr, "WARNING:  Received GDB command 0x%X (%c) while target running!\n", buf->data[0], buf->data[0]);
        }
        }
 
      return;
    }
    }
 
 
  switch (buf->data[0])
  switch (buf->data[0])
    {
    {
    case 0x03:
    case 0x03:
      fprintf(stderr, "Warning:  asynchronous BREAK received while target stopped.\n");
      fprintf(stderr, "Warning:  asynchronous BREAK received while target stopped.\n");
      return;
      return;
 
 
    case '!':
    case '!':
      /* Request for extended remote mode */
      /* Request for extended remote mode */
      put_str_packet ("OK");
      put_str_packet ("OK");
      return;
      return;
 
 
    case '?':
    case '?':
      /* Return last signal ID */
      /* Return last signal ID */
      rsp_report_exception();
      rsp_report_exception();
      return;
      return;
 
 
    case 'A':
    case 'A':
      /* Initialization of argv not supported */
      /* Initialization of argv not supported */
      fprintf (stderr, "Warning: RSP 'A' packet not supported: ignored\n");
      fprintf (stderr, "Warning: RSP 'A' packet not supported: ignored\n");
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
 
 
    case 'b':
    case 'b':
      /* Setting baud rate is deprecated */
      /* Setting baud rate is deprecated */
      fprintf (stderr, "Warning: RSP 'b' packet is deprecated and not "
      fprintf (stderr, "Warning: RSP 'b' packet is deprecated and not "
               "supported: ignored\n");
               "supported: ignored\n");
      return;
      return;
 
 
    case 'B':
    case 'B':
      /* Breakpoints should be set using Z packets */
      /* Breakpoints should be set using Z packets */
      fprintf (stderr, "Warning: RSP 'B' packet is deprecated (use 'Z'/'z' "
      fprintf (stderr, "Warning: RSP 'B' packet is deprecated (use 'Z'/'z' "
               "packets instead): ignored\n");
               "packets instead): ignored\n");
      return;
      return;
 
 
    case 'c':
    case 'c':
      /* Continue */
      /* Continue */
      rsp_continue (buf);
      rsp_continue (buf);
      return;
      return;
 
 
    case 'C':
    case 'C':
      /* Continue with signal */
      /* Continue with signal */
      rsp_continue_with_signal (buf);
      rsp_continue_with_signal (buf);
      return;
      return;
 
 
    case 'd':
    case 'd':
      /* Disable debug using a general query */
      /* Disable debug using a general query */
      fprintf (stderr, "Warning: RSP 'd' packet is deprecated (define a 'Q' "
      fprintf (stderr, "Warning: RSP 'd' packet is deprecated (define a 'Q' "
               "packet instead: ignored\n");
               "packet instead: ignored\n");
      return;
      return;
 
 
    case 'D':
    case 'D':
      /* Detach GDB. Do this by closing the client. The rules say that
      /* Detach GDB. Do this by closing the client. The rules say that
         execution should continue. TODO. Is this really then intended
         execution should continue. TODO. Is this really then intended
         meaning? Or does it just mean that only vAttach will be recognized
         meaning? Or does it just mean that only vAttach will be recognized
         after this? */
         after this? */
      put_str_packet ("OK");
      put_str_packet ("OK");
      rsp_client_close ();
      rsp_client_close ();
      set_stall_state (0);
      set_stall_state (0);
      return;
      return;
 
 
    case 'F':
    case 'F':
      /* File I/O is not currently supported */
      /* File I/O is not currently supported */
      fprintf (stderr, "Warning: RSP file I/O not currently supported: 'F' "
      fprintf (stderr, "Warning: RSP file I/O not currently supported: 'F' "
               "packet ignored\n");
               "packet ignored\n");
      return;
      return;
 
 
    case 'g':
    case 'g':
      rsp_read_all_regs ();
      rsp_read_all_regs ();
      return;
      return;
 
 
    case 'G':
    case 'G':
      rsp_write_all_regs (buf);
      rsp_write_all_regs (buf);
      return;
      return;
 
 
    case 'H':
    case 'H':
      /* Set the thread number of subsequent operations. For now ignore
      /* Set the thread number of subsequent operations. For now ignore
         silently and just reply "OK" */
         silently and just reply "OK" */
      put_str_packet ("OK");
      put_str_packet ("OK");
      return;
      return;
 
 
    case 'i':
    case 'i':
      /* Single instruction step */
      /* Single instruction step */
      rsp_step (buf);
      rsp_step (buf);
      return;
      return;
 
 
    case 'I':
    case 'I':
      /* Single instruction step with signal */
      /* Single instruction step with signal */
       rsp_step_with_signal (buf);
       rsp_step_with_signal (buf);
      return;
      return;
 
 
    case 'k':
    case 'k':
      /* Kill request. Do nothing for now. */
      /* Kill request. Do nothing for now. */
      return;
      return;
 
 
    case 'm':
    case 'm':
      /* Read memory (symbolic) */
      /* Read memory (symbolic) */
      rsp_read_mem (buf);
      rsp_read_mem (buf);
      return;
      return;
 
 
    case 'M':
    case 'M':
      /* Write memory (symbolic) */
      /* Write memory (symbolic) */
      rsp_write_mem (buf);
      rsp_write_mem (buf);
      return;
      return;
 
 
    case 'p':
    case 'p':
      /* Read a register */
      /* Read a register */
      rsp_read_reg (buf);
      rsp_read_reg (buf);
      return;
      return;
 
 
    case 'P':
    case 'P':
      /* Write a register */
      /* Write a register */
      rsp_write_reg (buf);
      rsp_write_reg (buf);
      return;
      return;
 
 
    case 'q':
    case 'q':
      /* Any one of a number of query packets */
      /* Any one of a number of query packets */
      rsp_query (buf);
      rsp_query (buf);
      return;
      return;
 
 
    case 'Q':
    case 'Q':
      /* Any one of a number of set packets */
      /* Any one of a number of set packets */
      rsp_set (buf);
      rsp_set (buf);
      return;
      return;
 
 
    case 'r':
    case 'r':
      /* Reset the system. Deprecated (use 'R' instead) */
      /* Reset the system. Deprecated (use 'R' instead) */
      fprintf (stderr, "Warning: RSP 'r' packet is deprecated (use 'R' "
      fprintf (stderr, "Warning: RSP 'r' packet is deprecated (use 'R' "
               "packet instead): ignored\n");
               "packet instead): ignored\n");
      return;
      return;
 
 
    case 'R':
    case 'R':
      /* Restart the program being debugged. */
      /* Restart the program being debugged. */
      rsp_restart ();
      rsp_restart ();
      return;
      return;
 
 
    case 's':
    case 's':
      /* Single step (one high level instruction). This could be hard without
      /* Single step (one high level instruction). This could be hard without
         DWARF2 info */
         DWARF2 info */
      rsp_step (buf);
      rsp_step (buf);
      return;
      return;
 
 
    case 'S':
    case 'S':
      /* Single step (one high level instruction) with signal. This could be
      /* Single step (one high level instruction) with signal. This could be
         hard without DWARF2 info */
         hard without DWARF2 info */
      rsp_step_with_signal (buf);
      rsp_step_with_signal (buf);
      return;
      return;
 
 
    case 't':
    case 't':
      /* Search. This is not well defined in the manual and for now we don't
      /* Search. This is not well defined in the manual and for now we don't
         support it. No response is defined. */
         support it. No response is defined. */
      fprintf (stderr, "Warning: RSP 't' packet not supported: ignored\n");
      fprintf (stderr, "Warning: RSP 't' packet not supported: ignored\n");
      return;
      return;
 
 
    case 'T':
    case 'T':
      /* Is the thread alive. We are bare metal, so don't have a thread
      /* Is the thread alive. We are bare metal, so don't have a thread
         context. The answer is always "OK". */
         context. The answer is always "OK". */
      put_str_packet ("OK");
      put_str_packet ("OK");
      return;
      return;
 
 
    case 'v':
    case 'v':
      /* Any one of a number of packets to control execution */
      /* Any one of a number of packets to control execution */
      rsp_vpkt (buf);
      rsp_vpkt (buf);
      return;
      return;
 
 
    case 'X':
    case 'X':
      /* Write memory (binary) */
      /* Write memory (binary) */
      rsp_write_mem_bin (buf);
      rsp_write_mem_bin (buf);
      return;
      return;
 
 
    case 'z':
    case 'z':
      /* Remove a breakpoint/watchpoint. */
      /* Remove a breakpoint/watchpoint. */
      rsp_remove_matchpoint (buf);
      rsp_remove_matchpoint (buf);
      return;
      return;
 
 
    case 'Z':
    case 'Z':
      /* Insert a breakpoint/watchpoint. */
      /* Insert a breakpoint/watchpoint. */
      rsp_insert_matchpoint (buf);
      rsp_insert_matchpoint (buf);
      return;
      return;
 
 
    default:
    default:
      /* Unknown commands are ignored */
      /* Unknown commands are ignored */
      fprintf (stderr, "Warning: Unknown RSP request %s\n", buf->data);
      fprintf (stderr, "Warning: Unknown RSP request %s\n", buf->data);
      return;
      return;
    }
    }
}       /* rsp_client_request () */
}       /* rsp_client_request () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Close the server if it is open                                            */
/*!Close the server if it is open                                            */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_server_close ()
rsp_server_close ()
{
{
  // Stop the target handler thread
  // Stop the target handler thread
  pthread_mutex_lock(&target_handler_mutex);
  pthread_mutex_lock(&target_handler_mutex);
  target_handler_state = 2;
  target_handler_state = 2;
  pthread_mutex_unlock(&target_handler_mutex);
  pthread_mutex_unlock(&target_handler_mutex);
 
 
  if (-1 != rsp.server_fd)
  if (-1 != rsp.server_fd)
    {
    {
      close (rsp.server_fd);
      close (rsp.server_fd);
      rsp.server_fd = -1;
      rsp.server_fd = -1;
    }
    }
}       /* rsp_server_close () */
}       /* rsp_server_close () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Close the client if it is open                                            */
/*!Close the client if it is open                                            */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_client_close ()
rsp_client_close ()
{
{
  unsigned char was_running = 0;
  unsigned char was_running = 0;
 
 
  // If target is running, stop it so we can modify SPRs
  // If target is running, stop it so we can modify SPRs
  pthread_mutex_lock(&rsp_mutex);
  pthread_mutex_lock(&rsp_mutex);
  was_running = rsp.target_running;
  was_running = rsp.target_running;
  pthread_mutex_unlock(&rsp_mutex);
  pthread_mutex_unlock(&rsp_mutex);
  if(was_running) {
  if(was_running) {
    set_stall_state(1);
    set_stall_state(1);
  }
  }
 
 
  // Clear the DSR: don't transfer control to the debug unit for any reason
  // Clear the DSR: don't transfer control to the debug unit for any reason
  dbg_cpu0_write(SPR_DSR, 0);
  dbg_cpu0_write(SPR_DSR, 0);
 
 
  // If target was running, restart it.
  // If target was running, restart it.
  if(was_running) {
  if(was_running) {
    set_stall_state(0);
    set_stall_state(0);
  }
  }
 
 
  // Stop the target handler thread.  MUST BE DONE AFTER THE LAST set_stall_state()!
  // Stop the target handler thread.  MUST BE DONE AFTER THE LAST set_stall_state()!
  pthread_mutex_lock(&target_handler_mutex);
  pthread_mutex_lock(&target_handler_mutex);
  target_handler_state = 0;
  target_handler_state = 0;
  pthread_mutex_unlock(&target_handler_mutex);
  pthread_mutex_unlock(&target_handler_mutex);
 
 
  if (-1 != rsp.client_fd)
  if (-1 != rsp.client_fd)
    {
    {
      close (rsp.client_fd);
      close (rsp.client_fd);
      rsp.client_fd = -1;
      rsp.client_fd = -1;
    }
    }
}       /* rsp_client_close () */
}       /* rsp_client_close () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Send a packet to the GDB client
/*!Send a packet to the GDB client
 
 
   Modeled on the stub version supplied with GDB. Put out the data preceded by
   Modeled on the stub version supplied with GDB. Put out the data preceded by
   a '$', followed by a '#' and a one byte checksum. '$', '#', '*' and '}' are
   a '$', followed by a '#' and a one byte checksum. '$', '#', '*' and '}' are
   escaped by preceding them with '}' and then XORing the character with
   escaped by preceding them with '}' and then XORing the character with
   0x20.
   0x20.
 
 
   @param[in] buf  The data to send                                          */
   @param[in] buf  The data to send                                          */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
put_packet (struct rsp_buf *buf)
put_packet (struct rsp_buf *buf)
{
{
  int  ch;                              /* Ack char */
  int  ch;                              /* Ack char */
 
 
  /* Construct $<packet info>#<checksum>. Repeat until the GDB client
  /* Construct $<packet info>#<checksum>. Repeat until the GDB client
     acknowledges satisfactory receipt. */
     acknowledges satisfactory receipt. */
  do
  do
    {
    {
      unsigned char checksum = 0;        /* Computed checksum */
      unsigned char checksum = 0;        /* Computed checksum */
      int           count    = 0;        /* Index into the buffer */
      int           count    = 0;        /* Index into the buffer */
 
 
#if RSP_TRACE
#if RSP_TRACE
      printf ("Putting %s\n", buf->data);
      printf ("Putting %s\n", buf->data);
      fflush (stdout);
      fflush (stdout);
#endif
#endif
 
 
      put_rsp_char ('$');               /* Start char */
      put_rsp_char ('$');               /* Start char */
 
 
      /* Body of the packet */
      /* Body of the packet */
      for (count = 0; count < buf->len; count++)
      for (count = 0; count < buf->len; count++)
        {
        {
          unsigned char  ch = buf->data[count];
          unsigned char  ch = buf->data[count];
 
 
          /* Check for escaped chars */
          /* Check for escaped chars */
          if (('$' == ch) || ('#' == ch) || ('*' == ch) || ('}' == ch))
          if (('$' == ch) || ('#' == ch) || ('*' == ch) || ('}' == ch))
            {
            {
              ch       ^= 0x20;
              ch       ^= 0x20;
              checksum += (unsigned char)'}';
              checksum += (unsigned char)'}';
              put_rsp_char ('}');
              put_rsp_char ('}');
            }
            }
 
 
          checksum += ch;
          checksum += ch;
          put_rsp_char (ch);
          put_rsp_char (ch);
        }
        }
 
 
      put_rsp_char ('#');               /* End char */
      put_rsp_char ('#');               /* End char */
 
 
      /* Computed checksum */
      /* Computed checksum */
      put_rsp_char (hexchars[checksum >> 4]);
      put_rsp_char (hexchars[checksum >> 4]);
      put_rsp_char (hexchars[checksum % 16]);
      put_rsp_char (hexchars[checksum % 16]);
 
 
      /* Check for ack of connection failure */
      /* Check for ack of connection failure */
      ch = get_rsp_char ();
      ch = get_rsp_char ();
      if (-1 == ch)
      if (-1 == ch)
        {
        {
          return;                       /* Fail the put silently. */
          return;                       /* Fail the put silently. */
        }
        }
    }
    }
  while ('+' != ch);
  while ('+' != ch);
 
 
}       /* put_packet () */
}       /* put_packet () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Convenience to put a constant string packet
/*!Convenience to put a constant string packet
 
 
   param[in] str  The text of the packet                                     */
   param[in] str  The text of the packet                                     */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
put_str_packet (const char *str)
put_str_packet (const char *str)
{
{
  struct rsp_buf  buf;
  struct rsp_buf  buf;
  int             len = strlen (str);
  int             len = strlen (str);
 
 
  /* Construct the packet to send, so long as string is not too big,
  /* Construct the packet to send, so long as string is not too big,
     otherwise truncate. Add EOS at the end for convenient debug printout */
     otherwise truncate. Add EOS at the end for convenient debug printout */
 
 
  if (len >= GDB_BUF_MAX)
  if (len >= GDB_BUF_MAX)
    {
    {
      fprintf (stderr, "Warning: String %s too large for RSP packet: "
      fprintf (stderr, "Warning: String %s too large for RSP packet: "
               "truncated\n", str);
               "truncated\n", str);
      len = GDB_BUF_MAX - 1;
      len = GDB_BUF_MAX - 1;
    }
    }
 
 
  strncpy (buf.data, str, len);
  strncpy (buf.data, str, len);
  buf.data[len] = 0;
  buf.data[len] = 0;
  buf.len       = len;
  buf.len       = len;
 
 
  put_packet (&buf);
  put_packet (&buf);
 
 
}       /* put_str_packet () */
}       /* put_str_packet () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Get a packet from the GDB client
/*!Get a packet from the GDB client
 
 
   Modeled on the stub version supplied with GDB. The data is in a static
   Modeled on the stub version supplied with GDB. The data is in a static
   buffer. The data should be copied elsewhere if it is to be preserved across
   buffer. The data should be copied elsewhere if it is to be preserved across
   a subsequent call to get_packet().
   a subsequent call to get_packet().
 
 
   Unlike the reference implementation, we don't deal with sequence
   Unlike the reference implementation, we don't deal with sequence
   numbers. GDB has never used them, and this implementation is only intended
   numbers. GDB has never used them, and this implementation is only intended
   for use with GDB 6.8 or later. Sequence numbers were removed from the RSP
   for use with GDB 6.8 or later. Sequence numbers were removed from the RSP
   standard at GDB 5.0.
   standard at GDB 5.0.
 
 
   @return  A pointer to the static buffer containing the data                */
   @return  A pointer to the static buffer containing the data                */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static struct rsp_buf *
static struct rsp_buf *
get_packet ()
get_packet ()
{
{
  static struct rsp_buf  buf;           /* Survives the return */
  static struct rsp_buf  buf;           /* Survives the return */
 
 
  /* Keep getting packets, until one is found with a valid checksum */
  /* Keep getting packets, until one is found with a valid checksum */
  while (1)
  while (1)
    {
    {
      unsigned char  checksum;          /* The checksum we have computed */
      unsigned char  checksum;          /* The checksum we have computed */
      int            count;             /* Index into the buffer */
      int            count;             /* Index into the buffer */
      int            ch;                /* Current character */
      int            ch;                /* Current character */
 
 
      /* Wait around for the start character ('$'). Ignore all other
      /* Wait around for the start character ('$'). Ignore all other
         characters */
         characters */
      ch = get_rsp_char ();
      ch = get_rsp_char ();
      while (ch != '$')
      while (ch != '$')
        {
        {
          if (-1 == ch)
          if (-1 == ch)
            {
            {
              return  NULL;             /* Connection failed */
              return  NULL;             /* Connection failed */
            }
            }
 
 
          // 0x03 is a special case, an out-of-band break when running
          // 0x03 is a special case, an out-of-band break when running
          if(ch == 0x03)
          if(ch == 0x03)
            {
            {
              buf.data[0] = ch;
              buf.data[0] = ch;
              buf.len     = 1;
              buf.len     = 1;
              return &buf;
              return &buf;
            }
            }
 
 
          ch = get_rsp_char ();
          ch = get_rsp_char ();
        }
        }
 
 
      /* Read until a '#' or end of buffer is found */
      /* Read until a '#' or end of buffer is found */
      checksum =  0;
      checksum =  0;
      count    =  0;
      count    =  0;
      while (count < GDB_BUF_MAX - 1)
      while (count < GDB_BUF_MAX - 1)
        {
        {
          ch = get_rsp_char ();
          ch = get_rsp_char ();
 
 
          /* Check for connection failure */
          /* Check for connection failure */
          if (-1 == ch)
          if (-1 == ch)
            {
            {
              return  NULL;
              return  NULL;
            }
            }
 
 
          /* If we hit a start of line char begin all over again */
          /* If we hit a start of line char begin all over again */
          if ('$' == ch)
          if ('$' == ch)
            {
            {
              checksum =  0;
              checksum =  0;
              count    =  0;
              count    =  0;
 
 
              continue;
              continue;
            }
            }
 
 
          /* Break out if we get the end of line char */
          /* Break out if we get the end of line char */
          if ('#' == ch)
          if ('#' == ch)
            {
            {
              break;
              break;
            }
            }
 
 
          /* Update the checksum and add the char to the buffer */
          /* Update the checksum and add the char to the buffer */
 
 
          checksum        = checksum + (unsigned char)ch;
          checksum        = checksum + (unsigned char)ch;
          buf.data[count] = (char)ch;
          buf.data[count] = (char)ch;
          count           = count + 1;
          count           = count + 1;
        }
        }
 
 
      /* Mark the end of the buffer with EOS - it's convenient for non-binary
      /* Mark the end of the buffer with EOS - it's convenient for non-binary
         data to be valid strings. */
         data to be valid strings. */
      buf.data[count] = 0;
      buf.data[count] = 0;
      buf.len         = count;
      buf.len         = count;
 
 
      /* If we have a valid end of packet char, validate the checksum */
      /* If we have a valid end of packet char, validate the checksum */
      if ('#' == ch)
      if ('#' == ch)
        {
        {
          unsigned char  xmitcsum;      /* The checksum in the packet */
          unsigned char  xmitcsum;      /* The checksum in the packet */
 
 
          ch = get_rsp_char ();
          ch = get_rsp_char ();
          if (-1 == ch)
          if (-1 == ch)
            {
            {
              return  NULL;             /* Connection failed */
              return  NULL;             /* Connection failed */
            }
            }
          xmitcsum = hex (ch) << 4;
          xmitcsum = hex (ch) << 4;
 
 
          ch = get_rsp_char ();
          ch = get_rsp_char ();
          if (-1 == ch)
          if (-1 == ch)
            {
            {
              return  NULL;             /* Connection failed */
              return  NULL;             /* Connection failed */
            }
            }
 
 
          xmitcsum += hex (ch);
          xmitcsum += hex (ch);
 
 
          /* If the checksums don't match print a warning, and put the
          /* If the checksums don't match print a warning, and put the
             negative ack back to the client. Otherwise put a positive ack. */
             negative ack back to the client. Otherwise put a positive ack. */
          if (checksum != xmitcsum)
          if (checksum != xmitcsum)
            {
            {
              fprintf (stderr, "Warning: Bad RSP checksum: Computed "
              fprintf (stderr, "Warning: Bad RSP checksum: Computed "
                       "0x%02x, received 0x%02x\n", checksum, xmitcsum);
                       "0x%02x, received 0x%02x\n", checksum, xmitcsum);
 
 
              put_rsp_char ('-');       /* Failed checksum */
              put_rsp_char ('-');       /* Failed checksum */
            }
            }
          else
          else
            {
            {
              put_rsp_char ('+');       /* successful transfer */
              put_rsp_char ('+');       /* successful transfer */
              break;
              break;
            }
            }
        }
        }
      else
      else
        {
        {
          fprintf (stderr, "Warning: RSP packet overran buffer\n");
          fprintf (stderr, "Warning: RSP packet overran buffer\n");
        }
        }
    }
    }
 
 
  return &buf;                          /* Success */
  return &buf;                          /* Success */
 
 
}       /* get_packet () */
}       /* get_packet () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Put a single character out onto the client socket
/*!Put a single character out onto the client socket
 
 
   This should only be called if the client is open, but we check for safety.
   This should only be called if the client is open, but we check for safety.
 
 
   @param[in] c  The character to put out                                    */
   @param[in] c  The character to put out                                    */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
put_rsp_char (char  c)
put_rsp_char (char  c)
{
{
  if (-1 == rsp.client_fd)
  if (-1 == rsp.client_fd)
    {
    {
      fprintf (stderr, "Warning: Attempt to write '%c' to unopened RSP "
      fprintf (stderr, "Warning: Attempt to write '%c' to unopened RSP "
               "client: Ignored\n", c);
               "client: Ignored\n", c);
      return;
      return;
    }
    }
 
 
  /* Write until successful (we retry after interrupts) or catastrophic
  /* Write until successful (we retry after interrupts) or catastrophic
     failure. */
     failure. */
  while (1)
  while (1)
    {
    {
      switch (write (rsp.client_fd, &c, sizeof (c)))
      switch (write (rsp.client_fd, &c, sizeof (c)))
        {
        {
        case -1:
        case -1:
          /* Error: only allow interrupts or would block */
          /* Error: only allow interrupts or would block */
          if ((EAGAIN != errno) && (EINTR != errno))
          if ((EAGAIN != errno) && (EINTR != errno))
            {
            {
              fprintf (stderr, "Warning: Failed to write to RSP client: "
              fprintf (stderr, "Warning: Failed to write to RSP client: "
                       "Closing client connection: %s\n",
                       "Closing client connection: %s\n",
                       strerror (errno));
                       strerror (errno));
              rsp_client_close ();
              rsp_client_close ();
              return;
              return;
            }
            }
 
 
          break;
          break;
 
 
        case 0:
        case 0:
          break;                /* Nothing written! Try again */
          break;                /* Nothing written! Try again */
 
 
        default:
        default:
          return;               /* Success, we can return */
          return;               /* Success, we can return */
        }
        }
    }
    }
}       /* put_rsp_char () */
}       /* put_rsp_char () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Get a single character from the client socket
/*!Get a single character from the client socket
 
 
   This should only be called if the client is open, but we check for safety.
   This should only be called if the client is open, but we check for safety.
 
 
   @return  The character read, or -1 on failure                             */
   @return  The character read, or -1 on failure                             */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static int
static int
get_rsp_char ()
get_rsp_char ()
{
{
  unsigned char  c;             /* The character read */
  unsigned char  c;             /* The character read */
 
 
  if (-1 == rsp.client_fd)
  if (-1 == rsp.client_fd)
    {
    {
      fprintf (stderr, "Warning: Attempt to read from unopened RSP "
      fprintf (stderr, "Warning: Attempt to read from unopened RSP "
               "client: Ignored\n");
               "client: Ignored\n");
      return  -1;
      return  -1;
    }
    }
 
 
  /* Read until successful (we retry after interrupts) or catastrophic
  /* Read until successful (we retry after interrupts) or catastrophic
     failure. */
     failure. */
  while (1)
  while (1)
    {
    {
      switch (read (rsp.client_fd, &c, sizeof (c)))
      switch (read (rsp.client_fd, &c, sizeof (c)))
        {
        {
        case -1:
        case -1:
          /* Error: only allow interrupts or would block */
          /* Error: only allow interrupts or would block */
          if ((EAGAIN != errno) && (EINTR != errno))
          if ((EAGAIN != errno) && (EINTR != errno))
            {
            {
              fprintf (stderr, "Warning: Failed to read from RSP client: "
              fprintf (stderr, "Warning: Failed to read from RSP client: "
                       "Closing client connection: %s\n",
                       "Closing client connection: %s\n",
                       strerror (errno));
                       strerror (errno));
              rsp_client_close ();
              rsp_client_close ();
              return  -1;
              return  -1;
            }
            }
 
 
          break;
          break;
 
 
        case 0:
        case 0:
          // EOF
          // EOF
          rsp_client_close ();
          rsp_client_close ();
          return  -1;
          return  -1;
 
 
        default:
        default:
          return  c & 0xff;     /* Success, we can return (no sign extend!) */
          return  c & 0xff;     /* Success, we can return (no sign extend!) */
        }
        }
    }
    }
}       /* get_rsp_char () */
}       /* get_rsp_char () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!"Unescape" RSP binary data
/*!"Unescape" RSP binary data
 
 
   '#', '$' and '}' are escaped by preceding them by '}' and oring with 0x20.
   '#', '$' and '}' are escaped by preceding them by '}' and oring with 0x20.
 
 
   This function reverses that, modifying the data in place.
   This function reverses that, modifying the data in place.
 
 
   @param[in] data  The array of bytes to convert
   @param[in] data  The array of bytes to convert
   @para[in]  len   The number of bytes to be converted
   @para[in]  len   The number of bytes to be converted
 
 
   @return  The number of bytes AFTER conversion                             */
   @return  The number of bytes AFTER conversion                             */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static int
static int
rsp_unescape (char *data,
rsp_unescape (char *data,
              int   len)
              int   len)
{
{
  int  from_off = 0;             /* Offset to source char */
  int  from_off = 0;             /* Offset to source char */
  int  to_off   = 0;             /* Offset to dest char */
  int  to_off   = 0;             /* Offset to dest char */
 
 
  while (from_off < len)
  while (from_off < len)
    {
    {
      /* Is it escaped */
      /* Is it escaped */
      if ( '}' == data[from_off])
      if ( '}' == data[from_off])
        {
        {
          from_off++;
          from_off++;
          data[to_off] = data[from_off] ^ 0x20;
          data[to_off] = data[from_off] ^ 0x20;
        }
        }
      else
      else
        {
        {
          data[to_off] = data[from_off];
          data[to_off] = data[from_off];
        }
        }
 
 
      from_off++;
      from_off++;
      to_off++;
      to_off++;
    }
    }
 
 
  return  to_off;
  return  to_off;
 
 
}       /* rsp_unescape () */
}       /* rsp_unescape () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Initialize the matchpoint hash table
/*!Initialize the matchpoint hash table
 
 
   This is an open hash table, so this function clears all the links to
   This is an open hash table, so this function clears all the links to
   NULL.                                                                     */
   NULL.                                                                     */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
mp_hash_init ()
mp_hash_init ()
{
{
  int  i;
  int  i;
 
 
  for (i = 0; i < MP_HASH_SIZE; i++)
  for (i = 0; i < MP_HASH_SIZE; i++)
    {
    {
      rsp.mp_hash[i] = NULL;
      rsp.mp_hash[i] = NULL;
    }
    }
}       /* mp_hash_init () */
}       /* mp_hash_init () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Add an entry to the matchpoint hash table
/*!Add an entry to the matchpoint hash table
 
 
   Add the entry if it wasn't already there. If it was there do nothing. The
   Add the entry if it wasn't already there. If it was there do nothing. The
   match just be on type and addr. The instr need not match, since if this is
   match just be on type and addr. The instr need not match, since if this is
   a duplicate insertion (perhaps due to a lost packet) they will be
   a duplicate insertion (perhaps due to a lost packet) they will be
   different.
   different.
 
 
   @param[in] type   The type of matchpoint
   @param[in] type   The type of matchpoint
   @param[in] addr   The address of the matchpoint
   @param[in] addr   The address of the matchpoint
   @para[in]  instr  The instruction to associate with the address           */
   @para[in]  instr  The instruction to associate with the address           */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
mp_hash_add (enum mp_type       type,
mp_hash_add (enum mp_type       type,
             unsigned long int  addr,
             unsigned long int  addr,
             unsigned long int  instr)
             unsigned long int  instr)
{
{
  int              hv    = addr % MP_HASH_SIZE;
  int              hv    = addr % MP_HASH_SIZE;
  struct mp_entry *curr;
  struct mp_entry *curr;
 
 
  /* See if we already have the entry */
  /* See if we already have the entry */
  for(curr = rsp.mp_hash[hv]; NULL != curr; curr = curr->next)
  for(curr = rsp.mp_hash[hv]; NULL != curr; curr = curr->next)
    {
    {
      if ((type == curr->type) && (addr == curr->addr))
      if ((type == curr->type) && (addr == curr->addr))
        {
        {
          return;               /* We already have the entry */
          return;               /* We already have the entry */
        }
        }
    }
    }
 
 
  /* Insert the new entry at the head of the chain */
  /* Insert the new entry at the head of the chain */
  curr = malloc (sizeof (*curr));
  curr = malloc (sizeof (*curr));
 
 
  curr->type  = type;
  curr->type  = type;
  curr->addr  = addr;
  curr->addr  = addr;
  curr->instr = instr;
  curr->instr = instr;
  curr->next  = rsp.mp_hash[hv];
  curr->next  = rsp.mp_hash[hv];
 
 
  rsp.mp_hash[hv] = curr;
  rsp.mp_hash[hv] = curr;
 
 
}       /* mp_hash_add () */
}       /* mp_hash_add () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Look up an entry in the matchpoint hash table
/*!Look up an entry in the matchpoint hash table
 
 
   The match must be on type AND addr.
   The match must be on type AND addr.
 
 
   @param[in] type   The type of matchpoint
   @param[in] type   The type of matchpoint
   @param[in] addr   The address of the matchpoint
   @param[in] addr   The address of the matchpoint
 
 
   @return  The entry deleted, or NULL if the entry was not found            */
   @return  The entry deleted, or NULL if the entry was not found            */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static struct mp_entry *
static struct mp_entry *
mp_hash_lookup (enum mp_type       type,
mp_hash_lookup (enum mp_type       type,
                unsigned long int  addr)
                unsigned long int  addr)
{
{
  int              hv   = addr % MP_HASH_SIZE;
  int              hv   = addr % MP_HASH_SIZE;
  struct mp_entry *curr;
  struct mp_entry *curr;
 
 
  /* Search */
  /* Search */
  for (curr = rsp.mp_hash[hv]; NULL != curr; curr = curr->next)
  for (curr = rsp.mp_hash[hv]; NULL != curr; curr = curr->next)
    {
    {
      if ((type == curr->type) && (addr == curr->addr))
      if ((type == curr->type) && (addr == curr->addr))
        {
        {
          return  curr;         /* The entry found */
          return  curr;         /* The entry found */
        }
        }
    }
    }
 
 
  /* Not found */
  /* Not found */
  return  NULL;
  return  NULL;
 
 
}       /* mp_hash_lookup () */
}       /* mp_hash_lookup () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Delete an entry from the matchpoint hash table
/*!Delete an entry from the matchpoint hash table
 
 
   If it is there the entry is deleted from the hash table. If it is not
   If it is there the entry is deleted from the hash table. If it is not
   there, no action is taken. The match must be on type AND addr.
   there, no action is taken. The match must be on type AND addr.
 
 
   The usual fun and games tracking the previous entry, so we can delete
   The usual fun and games tracking the previous entry, so we can delete
   things.
   things.
 
 
   @note  The deletion DOES NOT free the memory associated with the entry,
   @note  The deletion DOES NOT free the memory associated with the entry,
          since that is returned. The caller should free the memory when they
          since that is returned. The caller should free the memory when they
          have used the information.
          have used the information.
 
 
   @param[in] type   The type of matchpoint
   @param[in] type   The type of matchpoint
   @param[in] addr   The address of the matchpoint
   @param[in] addr   The address of the matchpoint
 
 
   @return  The entry deleted, or NULL if the entry was not found            */
   @return  The entry deleted, or NULL if the entry was not found            */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static struct mp_entry *
static struct mp_entry *
mp_hash_delete (enum mp_type       type,
mp_hash_delete (enum mp_type       type,
                unsigned long int  addr)
                unsigned long int  addr)
{
{
  int              hv   = addr % MP_HASH_SIZE;
  int              hv   = addr % MP_HASH_SIZE;
  struct mp_entry *prev = NULL;
  struct mp_entry *prev = NULL;
  struct mp_entry *curr;
  struct mp_entry *curr;
 
 
  /* Search */
  /* Search */
  for (curr  = rsp.mp_hash[hv]; NULL != curr; curr = curr->next)
  for (curr  = rsp.mp_hash[hv]; NULL != curr; curr = curr->next)
    {
    {
      if ((type == curr->type) && (addr == curr->addr))
      if ((type == curr->type) && (addr == curr->addr))
        {
        {
          /* Found - delete. Method depends on whether we are the head of
          /* Found - delete. Method depends on whether we are the head of
             chain. */
             chain. */
          if (NULL == prev)
          if (NULL == prev)
            {
            {
              rsp.mp_hash[hv] = curr->next;
              rsp.mp_hash[hv] = curr->next;
            }
            }
          else
          else
            {
            {
              prev->next = curr->next;
              prev->next = curr->next;
            }
            }
 
 
          return  curr;         /* The entry deleted */
          return  curr;         /* The entry deleted */
        }
        }
 
 
      prev = curr;
      prev = curr;
    }
    }
 
 
  /* Not found */
  /* Not found */
  return  NULL;
  return  NULL;
 
 
}       /* mp_hash_delete () */
}       /* mp_hash_delete () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Utility to give the value of a hex char
/*!Utility to give the value of a hex char
 
 
   @param[in] ch  A character representing a hexadecimal digit. Done as -1,
   @param[in] ch  A character representing a hexadecimal digit. Done as -1,
                  for consistency with other character routines, which can use
                  for consistency with other character routines, which can use
                  -1 as EOF.
                  -1 as EOF.
 
 
   @return  The value of the hex character, or -1 if the character is
   @return  The value of the hex character, or -1 if the character is
            invalid.                                                         */
            invalid.                                                         */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static int
static int
hex (int  c)
hex (int  c)
{
{
  return  ((c >= 'a') && (c <= 'f')) ? c - 'a' + 10 :
  return  ((c >= 'a') && (c <= 'f')) ? c - 'a' + 10 :
          ((c >= '0') && (c <= '9')) ? c - '0' :
          ((c >= '0') && (c <= '9')) ? c - '0' :
          ((c >= 'A') && (c <= 'F')) ? c - 'A' + 10 : -1;
          ((c >= 'A') && (c <= 'F')) ? c - 'A' + 10 : -1;
 
 
}       /* hex () */
}       /* hex () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Convert a register to a hex digit string
/*!Convert a register to a hex digit string
 
 
   The supplied 32-bit value is converted to an 8 digit hex string according
   The supplied 32-bit value is converted to an 8 digit hex string according
   the target endianism. It is null terminated for convenient printing.
   the target endianism. It is null terminated for convenient printing.
 
 
   @param[in]  val  The value to convert
   @param[in]  val  The value to convert
   @param[out] buf  The buffer for the text string                           */
   @param[out] buf  The buffer for the text string                           */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
reg2hex (unsigned long int  val,
reg2hex (unsigned long int  val,
         char              *buf)
         char              *buf)
{
{
  int  n;                       /* Counter for digits */
  int  n;                       /* Counter for digits */
 
 
  for (n = 0; n < 8; n++)
  for (n = 0; n < 8; n++)
    {
    {
#ifdef WORDSBIGENDIAN
#ifdef WORDSBIGENDIAN
      int  nyb_shift = n * 4;
      int  nyb_shift = n * 4;
#else
#else
      int  nyb_shift = 28 - (n * 4);
      int  nyb_shift = 28 - (n * 4);
#endif
#endif
      buf[n] = hexchars[(val >> nyb_shift) & 0xf];
      buf[n] = hexchars[(val >> nyb_shift) & 0xf];
    }
    }
 
 
  buf[8] = 0;                    /* Useful to terminate as string */
  buf[8] = 0;                    /* Useful to terminate as string */
 
 
}       /* reg2hex () */
}       /* reg2hex () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Convert a hex digit string to a register value
/*!Convert a hex digit string to a register value
 
 
   The supplied 8 digit hex string is converted to a 32-bit value according
   The supplied 8 digit hex string is converted to a 32-bit value according
   the target endianism
   the target endianism
 
 
   @param[in] buf  The buffer with the hex string
   @param[in] buf  The buffer with the hex string
 
 
   @return  The value to convert                                             */
   @return  The value to convert                                             */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static unsigned long int
static unsigned long int
hex2reg (char *buf)
hex2reg (char *buf)
{
{
  int                n;         /* Counter for digits */
  int                n;         /* Counter for digits */
  unsigned long int  val = 0;    /* The result */
  unsigned long int  val = 0;    /* The result */
 
 
  for (n = 0; n < 8; n++)
  for (n = 0; n < 8; n++)
    {
    {
#ifdef WORDSBIGENDIAN
#ifdef WORDSBIGENDIAN
      int  nyb_shift = n * 4;
      int  nyb_shift = n * 4;
#else
#else
      int  nyb_shift = 28 - (n * 4);
      int  nyb_shift = 28 - (n * 4);
#endif
#endif
      val |= hex (buf[n]) << nyb_shift;
      val |= hex (buf[n]) << nyb_shift;
    }
    }
 
 
  return val;
  return val;
 
 
}       /* hex2reg () */
}       /* hex2reg () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Convert an ASCII character string to pairs of hex digits
/*!Convert an ASCII character string to pairs of hex digits
 
 
   Both source and destination are null terminated.
   Both source and destination are null terminated.
 
 
   @param[out] dest  Buffer to store the hex digit pairs (null terminated)
   @param[out] dest  Buffer to store the hex digit pairs (null terminated)
   @param[in]  src   The ASCII string (null terminated)                      */
   @param[in]  src   The ASCII string (null terminated)                      */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void  ascii2hex (char *dest,
static void  ascii2hex (char *dest,
                        char *src)
                        char *src)
{
{
  int  i;
  int  i;
 
 
  /* Step through converting the source string */
  /* Step through converting the source string */
  for (i = 0; src[i] != '\0'; i++)
  for (i = 0; src[i] != '\0'; i++)
    {
    {
      char  ch = src[i];
      char  ch = src[i];
 
 
      dest[i * 2]     = hexchars[ch >> 4 & 0xf];
      dest[i * 2]     = hexchars[ch >> 4 & 0xf];
      dest[i * 2 + 1] = hexchars[ch      & 0xf];
      dest[i * 2 + 1] = hexchars[ch      & 0xf];
    }
    }
 
 
  dest[i * 2] = '\0';
  dest[i * 2] = '\0';
 
 
}       /* ascii2hex () */
}       /* ascii2hex () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Convert pairs of hex digits to an ASCII character string
/*!Convert pairs of hex digits to an ASCII character string
 
 
   Both source and destination are null terminated.
   Both source and destination are null terminated.
 
 
   @param[out] dest  The ASCII string (null terminated)
   @param[out] dest  The ASCII string (null terminated)
   @param[in]  src   Buffer holding the hex digit pairs (null terminated)    */
   @param[in]  src   Buffer holding the hex digit pairs (null terminated)    */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void  hex2ascii (char *dest,
static void  hex2ascii (char *dest,
                        char *src)
                        char *src)
{
{
  int  i;
  int  i;
 
 
  /* Step through convering the source hex digit pairs */
  /* Step through convering the source hex digit pairs */
  for (i = 0; src[i * 2] != '\0' && src[i * 2 + 1] != '\0'; i++)
  for (i = 0; src[i * 2] != '\0' && src[i * 2 + 1] != '\0'; i++)
    {
    {
      dest[i] = ((hex (src[i * 2]) & 0xf) << 4) | (hex (src[i * 2 + 1]) & 0xf);
      dest[i] = ((hex (src[i * 2]) & 0xf) << 4) | (hex (src[i * 2 + 1]) & 0xf);
    }
    }
 
 
  dest[i] = '\0';
  dest[i] = '\0';
 
 
}       /* hex2ascii () */
}       /* hex2ascii () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the program counter
/*!Set the program counter
 
 
   This sets the value in the NPC SPR. Not completely trivial, since this is
   This sets the value in the NPC SPR. Not completely trivial, since this is
   actually cached in cpu_state.pc. Any reset of the NPC also involves
   actually cached in cpu_state.pc. Any reset of the NPC also involves
   clearing the delay state and setting the pcnext global.
   clearing the delay state and setting the pcnext global.
 
 
   Only actually do this if the requested address is different to the current
   Only actually do this if the requested address is different to the current
   NPC (avoids clearing the delay pipe).
   NPC (avoids clearing the delay pipe).
 
 
   @param[in] addr  The address to use                                       */
   @param[in] addr  The address to use                                       */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static unsigned int set_npc (unsigned long int  addr)
static unsigned int set_npc (unsigned long int  addr)
{
{
  int errcode;
  int errcode;
 
 
  errcode = dbg_cpu0_write(SPR_NPC, addr);
  errcode = dbg_cpu0_write(SPR_NPC, addr);
  cached_npc = addr;
  cached_npc = addr;
  use_cached_npc = 1;
  use_cached_npc = 1;
 
 
  /*  This was done in the simulator.  Is any of this necessary on the hardware?  --NAY
  /*  This was done in the simulator.  Is any of this necessary on the hardware?  --NAY
    if (cpu_state.pc != addr)
    if (cpu_state.pc != addr)
    {
    {
    cpu_state.pc         = addr;
    cpu_state.pc         = addr;
    cpu_state.delay_insn = 0;
    cpu_state.delay_insn = 0;
    pcnext               = addr + 4;
    pcnext               = addr + 4;
    }
    }
  */
  */
  return errcode;
  return errcode;
}       /* set_npc () */
}       /* set_npc () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Send a packet acknowledging an exception has occurred
/*!Send a packet acknowledging an exception has occurred
 
 
   This is only called if there is a client FD to talk to                    */
   This is only called if there is a client FD to talk to                    */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_report_exception ()
rsp_report_exception ()
{
{
  struct rsp_buf  buf;
  struct rsp_buf  buf;
 
 
  /* Construct a signal received packet */
  /* Construct a signal received packet */
  buf.data[0] = 'S';
  buf.data[0] = 'S';
  buf.data[1] = hexchars[rsp.sigval >> 4];
  buf.data[1] = hexchars[rsp.sigval >> 4];
  buf.data[2] = hexchars[rsp.sigval % 16];
  buf.data[2] = hexchars[rsp.sigval % 16];
  buf.data[3] = 0;
  buf.data[3] = 0;
  buf.len     = strlen (buf.data);
  buf.len     = strlen (buf.data);
 
 
  put_packet (&buf);
  put_packet (&buf);
 
 
}       /* rsp_report_exception () */
}       /* rsp_report_exception () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP continue request
/*!Handle a RSP continue request
 
 
   Parse the command to see if there is an address. Uses the underlying
   Parse the command to see if there is an address. Uses the underlying
   generic continue function, with EXCEPT_NONE.
   generic continue function, with EXCEPT_NONE.
 
 
   @param[in] buf  The full continue packet                                  */
   @param[in] buf  The full continue packet                                  */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_continue (struct rsp_buf *buf)
rsp_continue (struct rsp_buf *buf)
{
{
  unsigned long int  addr;              /* Address to continue from, if any */
  unsigned long int  addr;              /* Address to continue from, if any */
 
 
  if (strncmp(buf->data, "c", 2))
  if (strncmp(buf->data, "c", 2))
    {
    {
      if(1 != sscanf (buf->data, "c%lx", &addr))
      if(1 != sscanf (buf->data, "c%lx", &addr))
        {
        {
          fprintf (stderr,
          fprintf (stderr,
                   "Warning: RSP continue address %s not recognized: ignored\n",
                   "Warning: RSP continue address %s not recognized: ignored\n",
                   buf->data);
                   buf->data);
        }
        }
      else
      else
        {
        {
          /* Set the address as the value of the next program counter */
          /* Set the address as the value of the next program counter */
          // TODO Is support for this really that simple?  --NAY
          // TODO Is support for this really that simple?  --NAY
          set_npc (addr);
          set_npc (addr);
        }
        }
    }
    }
 
 
  rsp_continue_generic (EXCEPT_NONE);
  rsp_continue_generic (EXCEPT_NONE);
 
 
}       /* rsp_continue () */
}       /* rsp_continue () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP continue with signal request
/*!Handle a RSP continue with signal request
 
 
   Currently null. Will use the underlying generic continue function.
   Currently null. Will use the underlying generic continue function.
 
 
   @param[in] buf  The full continue with signal packet                      */
   @param[in] buf  The full continue with signal packet                      */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_continue_with_signal (struct rsp_buf *buf)
rsp_continue_with_signal (struct rsp_buf *buf)
{
{
  printf ("RSP continue with signal '%s' received\n", buf->data);
  printf ("RSP continue with signal '%s' received\n", buf->data);
 
 
}       /* rsp_continue_with_signal () */
}       /* rsp_continue_with_signal () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Generic processing of a continue request
/*!Generic processing of a continue request
 
 
   The signal may be EXCEPT_NONE if there is no exception to be
   The signal may be EXCEPT_NONE if there is no exception to be
   handled. Currently the exception is ignored.
   handled. Currently the exception is ignored.
 
 
   The single step flag is cleared in the debug registers and then the
   The single step flag is cleared in the debug registers and then the
   processor is unstalled.
   processor is unstalled.
 
 
   @param[in] addr    Address from which to step
   @param[in] addr    Address from which to step
   @param[in] except  The exception to use (if any)                          */
   @param[in] except  The exception to use (if any)                          */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_continue_generic (unsigned long int  except)
rsp_continue_generic (unsigned long int  except)
{
{
  unsigned long tmp;
  unsigned long tmp;
 
 
  /* Clear Debug Reason Register and watchpoint break generation in Debug Mode
  /* Clear Debug Reason Register and watchpoint break generation in Debug Mode
     Register 2 */
     Register 2 */
  dbg_cpu0_write(SPR_DRR, 0);
  dbg_cpu0_write(SPR_DRR, 0);
  dbg_cpu0_read(SPR_DMR2, &tmp);
  dbg_cpu0_read(SPR_DMR2, &tmp);
  tmp &= ~SPR_DMR2_WGB;
  tmp &= ~SPR_DMR2_WGB;
  dbg_cpu0_write(SPR_DMR2, tmp);
  dbg_cpu0_write(SPR_DMR2, tmp);
 
 
  /* Clear the single step trigger in Debug Mode Register 1 and set traps to be
  /* Clear the single step trigger in Debug Mode Register 1 and set traps to be
     handled by the debug unit in the Debug Stop Register */
     handled by the debug unit in the Debug Stop Register */
  dbg_cpu0_read(SPR_DMR1, &tmp);
  dbg_cpu0_read(SPR_DMR1, &tmp);
  tmp &= ~(SPR_DMR1_ST|SPR_DMR1_BT); // clear single-step and trap-on-branch
  tmp &= ~(SPR_DMR1_ST|SPR_DMR1_BT); // clear single-step and trap-on-branch
  dbg_cpu0_write(SPR_DMR1, tmp);
  dbg_cpu0_write(SPR_DMR1, tmp);
 
 
  // *** TODO Is there ever a situation where the DSR will not be set to give us control on a TRAP?  --NAY
  // *** TODO Is there ever a situation where the DSR will not be set to give us control on a TRAP?  --NAY
 
 
  /* Unstall the processor (also starts the target handler thread) */
  /* Unstall the processor (also starts the target handler thread) */
  set_stall_state (0);
  set_stall_state (0);
 
 
  /* Note the GDB client is now waiting for a reply. */
  /* Note the GDB client is now waiting for a reply. */
  rsp.client_waiting = 1;
  rsp.client_waiting = 1;
  rsp.single_step_mode = 0;
  rsp.single_step_mode = 0;
 
 
}       /* rsp_continue_generic () */
}       /* rsp_continue_generic () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP read all registers request
/*!Handle a RSP read all registers request
 
 
   The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PPC
   The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PPC
   (i.e. SPR PPC), NPC (i.e. SPR NPC) and SR (i.e. SPR SR). Each register is
   (i.e. SPR PPC), NPC (i.e. SPR NPC) and SR (i.e. SPR SR). Each register is
   returned as a sequence of bytes in target endian order.
   returned as a sequence of bytes in target endian order.
 
 
   Each byte is packed as a pair of hex digits.                              */
   Each byte is packed as a pair of hex digits.                              */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_read_all_regs ()
rsp_read_all_regs ()
{
{
  struct rsp_buf  buf;                  /* Buffer for the reply */
  struct rsp_buf  buf;                  /* Buffer for the reply */
  int             r;                    /* Register index */
  int             r;                    /* Register index */
  unsigned long regbuf[MAX_GPRS];
  unsigned long regbuf[MAX_GPRS];
  unsigned int errcode = APP_ERR_NONE;
  unsigned int errcode = APP_ERR_NONE;
 
 
  // Read all the GPRs in a single burst, for efficiency
  // Read all the GPRs in a single burst, for efficiency
  errcode = dbg_cpu0_read_block(SPR_GPR_BASE, regbuf, MAX_GPRS);
  errcode = dbg_cpu0_read_block(SPR_GPR_BASE, regbuf, MAX_GPRS);
 
 
  /* Format the GPR data for output */
  /* Format the GPR data for output */
  for (r = 0; r < MAX_GPRS; r++)
  for (r = 0; r < MAX_GPRS; r++)
    {
    {
      reg2hex(regbuf[r], &(buf.data[r * 8]));
      reg2hex(regbuf[r], &(buf.data[r * 8]));
    }
    }
 
 
  /* PPC, NPC and SR have consecutive addresses, read in one burst */
  /* PPC, NPC and SR have consecutive addresses, read in one burst */
  errcode |= dbg_cpu0_read_block(SPR_NPC, regbuf, 3);
  errcode |= dbg_cpu0_read_block(SPR_NPC, regbuf, 3);
 
 
  // Note that reg2hex adds a NULL terminator; as such, they must be
  // Note that reg2hex adds a NULL terminator; as such, they must be
  // put in buf.data in numerical order:  PPC, NPC, SR
  // put in buf.data in numerical order:  PPC, NPC, SR
  reg2hex(regbuf[2], &(buf.data[PPC_REGNUM * 8]));
  reg2hex(regbuf[2], &(buf.data[PPC_REGNUM * 8]));
 
 
  if(use_cached_npc == 1) {  // Hackery to work around CPU hardware quirk 
  if(use_cached_npc == 1) {  // Hackery to work around CPU hardware quirk 
    reg2hex(cached_npc, &(buf.data[NPC_REGNUM * 8]));
    reg2hex(cached_npc, &(buf.data[NPC_REGNUM * 8]));
  }
  }
  else {
  else {
    reg2hex(regbuf[0], &(buf.data[NPC_REGNUM * 8]));
    reg2hex(regbuf[0], &(buf.data[NPC_REGNUM * 8]));
  }
  }
 
 
  reg2hex(regbuf[1], &(buf.data[SR_REGNUM  * 8]));
  reg2hex(regbuf[1], &(buf.data[SR_REGNUM  * 8]));
 
 
  //fprintf(stderr, "Read SPRs:  0x%08X, 0x%08X, 0x%08X\n", regbuf[0], regbuf[1], regbuf[2]);
  //fprintf(stderr, "Read SPRs:  0x%08X, 0x%08X, 0x%08X\n", regbuf[0], regbuf[1], regbuf[2]);
 
 
  /*
  /*
  dbg_cpu0_read(SPR_PPC, &tmp);
  dbg_cpu0_read(SPR_PPC, &tmp);
  reg2hex(tmp, &(buf.data[PPC_REGNUM * 8]));
  reg2hex(tmp, &(buf.data[PPC_REGNUM * 8]));
 
 
  if(use_cached_npc == 1) {  // Hackery to work around CPU hardware quirk
  if(use_cached_npc == 1) {  // Hackery to work around CPU hardware quirk
    tmp = cached_npc;
    tmp = cached_npc;
  }
  }
  else {
  else {
    dbg_cpu0_read(SPR_NPC, &tmp);
    dbg_cpu0_read(SPR_NPC, &tmp);
  }
  }
  reg2hex(tmp, &(buf.data[NPC_REGNUM * 8]));
  reg2hex(tmp, &(buf.data[NPC_REGNUM * 8]));
 
 
  dbg_cpu0_read(SPR_SR, &tmp);
  dbg_cpu0_read(SPR_SR, &tmp);
  reg2hex(tmp, &(buf.data[SR_REGNUM  * 8]));
  reg2hex(tmp, &(buf.data[SR_REGNUM  * 8]));
  */
  */
 
 
  if(errcode == APP_ERR_NONE) {
  if(errcode == APP_ERR_NONE) {
    /* Finalize the packet and send it */
    /* Finalize the packet and send it */
    buf.data[NUM_REGS * 8] = 0;
    buf.data[NUM_REGS * 8] = 0;
    buf.len                = NUM_REGS * 8;
    buf.len                = NUM_REGS * 8;
    put_packet (&buf);
    put_packet (&buf);
  }
  }
  else {
  else {
    fprintf(stderr, "Error while reading all registers: %s\n", get_err_string(errcode));
    fprintf(stderr, "Error while reading all registers: %s\n", get_err_string(errcode));
    put_str_packet("E01");
    put_str_packet("E01");
  }
  }
 
 
}       /* rsp_read_all_regs () */
}       /* rsp_read_all_regs () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP write all registers request
/*!Handle a RSP write all registers request
 
 
   The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PPC
   The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PPC
   (i.e. SPR PPC), NPC (i.e. SPR NPC) and SR (i.e. SPR SR). Each register is
   (i.e. SPR PPC), NPC (i.e. SPR NPC) and SR (i.e. SPR SR). Each register is
   supplied as a sequence of bytes in target endian order.
   supplied as a sequence of bytes in target endian order.
 
 
   Each byte is packed as a pair of hex digits.
   Each byte is packed as a pair of hex digits.
 
 
   @todo There is no error checking at present. Non-hex chars will generate a
   @todo There is no error checking at present. Non-hex chars will generate a
         warning message, but there is no other check that the right amount
         warning message, but there is no other check that the right amount
         of data is present. The result is always "OK".
         of data is present. The result is always "OK".
 
 
   @param[in] buf  The original packet request.                              */
   @param[in] buf  The original packet request.                              */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_write_all_regs (struct rsp_buf *buf)
rsp_write_all_regs (struct rsp_buf *buf)
{
{
  int             r;                    /* Register index */
  int             r;                    /* Register index */
  unsigned long regbuf[MAX_GPRS];
  unsigned long regbuf[MAX_GPRS];
  unsigned int errcode;
  unsigned int errcode;
 
 
  /* The GPRs */
  /* The GPRs */
  for (r = 0; r < MAX_GPRS; r++)
  for (r = 0; r < MAX_GPRS; r++)
    {
    {
      // Set up the data for a burst access
      // Set up the data for a burst access
      regbuf[r] = hex2reg (&(buf->data[r * 8]));
      regbuf[r] = hex2reg (&(buf->data[r * 8]));
    }
    }
 
 
  errcode = dbg_cpu0_write_block(SPR_GPR_BASE, regbuf, MAX_GPRS);
  errcode = dbg_cpu0_write_block(SPR_GPR_BASE, regbuf, MAX_GPRS);
 
 
  /* PPC, NPC and SR */
  /* PPC, NPC and SR */
  regbuf[0] = hex2reg (&(buf->data[NPC_REGNUM * 8]));
  regbuf[0] = hex2reg (&(buf->data[NPC_REGNUM * 8]));
  regbuf[1] = hex2reg (&(buf->data[SR_REGNUM  * 8]));
  regbuf[1] = hex2reg (&(buf->data[SR_REGNUM  * 8]));
  regbuf[2] = hex2reg (&(buf->data[PPC_REGNUM * 8]));
  regbuf[2] = hex2reg (&(buf->data[PPC_REGNUM * 8]));
 
 
  errcode |= dbg_cpu0_write_block(SPR_NPC, regbuf, 3);
  errcode |= dbg_cpu0_write_block(SPR_NPC, regbuf, 3);
 
 
  /*
  /*
  tmp = hex2reg (&(buf->data[PPC_REGNUM * 8]));
  tmp = hex2reg (&(buf->data[PPC_REGNUM * 8]));
  dbg_cpu0_write(SPR_PPC, tmp);
  dbg_cpu0_write(SPR_PPC, tmp);
 
 
  tmp = hex2reg (&(buf->data[SR_REGNUM  * 8]));
  tmp = hex2reg (&(buf->data[SR_REGNUM  * 8]));
  dbg_cpu0_write(SPR_SR, tmp);
  dbg_cpu0_write(SPR_SR, tmp);
 
 
  tmp = hex2reg (&(buf->data[NPC_REGNUM * 8]));
  tmp = hex2reg (&(buf->data[NPC_REGNUM * 8]));
  dbg_cpu0_write(SPR_NPC, tmp);
  dbg_cpu0_write(SPR_NPC, tmp);
  */
  */
 
 
  if(errcode == APP_ERR_NONE)
  if(errcode == APP_ERR_NONE)
    put_str_packet ("OK");
    put_str_packet ("OK");
  else {
  else {
    fprintf(stderr, "Error while writing all registers: %s\n", get_err_string(errcode));
    fprintf(stderr, "Error while writing all registers: %s\n", get_err_string(errcode));
    put_str_packet("E01");
    put_str_packet("E01");
  }
  }
 
 
}       /* rsp_write_all_regs () */
}       /* rsp_write_all_regs () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP read memory (symbolic) request
/*!Handle a RSP read memory (symbolic) request
 
 
   Syntax is:
   Syntax is:
 
 
     m<addr>,<length>:
     m<addr>,<length>:
 
 
   The response is the bytes, lowest address first, encoded as pairs of hex
   The response is the bytes, lowest address first, encoded as pairs of hex
   digits.
   digits.
 
 
   The length given is the number of bytes to be read.
   The length given is the number of bytes to be read.
 
 
   @note This function reuses buf, so trashes the original command.
   @note This function reuses buf, so trashes the original command.
 
 
   @param[in] buf  The command received                                      */
   @param[in] buf  The command received                                      */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_read_mem (struct rsp_buf *buf)
rsp_read_mem (struct rsp_buf *buf)
{
{
  unsigned int    addr;                 /* Where to read the memory */
  unsigned int    addr;                 /* Where to read the memory */
  int             len;                  /* Number of bytes to read */
  int             len;                  /* Number of bytes to read */
  int             off;                  /* Offset into the memory */
  int             off;                  /* Offset into the memory */
  unsigned int errcode = APP_ERR_NONE;
  unsigned int errcode = APP_ERR_NONE;
 
 
  if (2 != sscanf (buf->data, "m%x,%x:", &addr, &len))
  if (2 != sscanf (buf->data, "m%x,%x:", &addr, &len))
    {
    {
      fprintf (stderr, "Warning: Failed to recognize RSP read memory "
      fprintf (stderr, "Warning: Failed to recognize RSP read memory "
               "command: %s\n", buf->data);
               "command: %s\n", buf->data);
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
    }
    }
 
 
  /* Make sure we won't overflow the buffer (2 chars per byte) */
  /* Make sure we won't overflow the buffer (2 chars per byte) */
  if ((len * 2) >= GDB_BUF_MAX)
  if ((len * 2) >= GDB_BUF_MAX)
    {
    {
      fprintf (stderr, "Warning: Memory read %s too large for RSP packet: "
      fprintf (stderr, "Warning: Memory read %s too large for RSP packet: "
               "truncated\n", buf->data);
               "truncated\n", buf->data);
      len = (GDB_BUF_MAX - 1) / 2;
      len = (GDB_BUF_MAX - 1) / 2;
    }
    }
 
 
  // Do the memory read into a temporary buffer
  // Do the memory read into a temporary buffer
  unsigned char *tmpbuf = (unsigned char *) malloc(len);  // *** TODO check return, don't always malloc (use realloc)
  unsigned char *tmpbuf = (unsigned char *) malloc(len);  // *** TODO check return, don't always malloc (use realloc)
  errcode = dbg_wb_read_block8(addr, tmpbuf, len);
  errcode = dbg_wb_read_block8(addr, tmpbuf, len);
 
 
 
 
  /* Refill the buffer with the reply */
  /* Refill the buffer with the reply */
  for (off = 0; off < len; off++)
  for (off = 0; off < len; off++)
    {
    {
      unsigned char  ch;                /* The byte at the address */
      unsigned char  ch;                /* The byte at the address */
 
 
      /* Check memory area is valid. Not really possible without knowing hardware configuration. */
      /* Check memory area is valid. Not really possible without knowing hardware configuration. */
 
 
      // Get the memory direct - no translation.
      // Get the memory direct - no translation.
      ch = tmpbuf[off];
      ch = tmpbuf[off];
      buf->data[off * 2]     = hexchars[ch >>   4];
      buf->data[off * 2]     = hexchars[ch >>   4];
      buf->data[off * 2 + 1] = hexchars[ch &  0xf];
      buf->data[off * 2 + 1] = hexchars[ch &  0xf];
    }
    }
 
 
  free(tmpbuf);
  free(tmpbuf);
 
 
  if(errcode == APP_ERR_NONE) {
  if(errcode == APP_ERR_NONE) {
    buf->data[off * 2] = 0;                      /* End of string */
    buf->data[off * 2] = 0;                      /* End of string */
    buf->len           = strlen (buf->data);
    buf->len           = strlen (buf->data);
    put_packet (buf);
    put_packet (buf);
  }
  }
  else {
  else {
    fprintf(stderr, "Error reading memory: %s\n", get_err_string(errcode));
    fprintf(stderr, "Error reading memory: %s\n", get_err_string(errcode));
    put_str_packet("E01");
    put_str_packet("E01");
  }
  }
 
 
}       /* rsp_read_mem () */
}       /* rsp_read_mem () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP write memory (symbolic) request
/*!Handle a RSP write memory (symbolic) request
 
 
   Syntax is:
   Syntax is:
 
 
     m<addr>,<length>:<data>
     m<addr>,<length>:<data>
 
 
   The data is the bytes, lowest address first, encoded as pairs of hex
   The data is the bytes, lowest address first, encoded as pairs of hex
   digits.
   digits.
 
 
   The length given is the number of bytes to be written.
   The length given is the number of bytes to be written.
 
 
   @note This function reuses buf, so trashes the original command.
   @note This function reuses buf, so trashes the original command.
 
 
   @param[in] buf  The command received                                      */
   @param[in] buf  The command received                                      */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_write_mem (struct rsp_buf *buf)
rsp_write_mem (struct rsp_buf *buf)
{
{
  unsigned int    addr;                 /* Where to write the memory */
  unsigned int    addr;                 /* Where to write the memory */
  int             len;                  /* Number of bytes to write */
  int             len;                  /* Number of bytes to write */
  char           *symdat;               /* Pointer to the symboli data */
  char           *symdat;               /* Pointer to the symboli data */
  int             datlen;               /* Number of digits in symbolic data */
  int             datlen;               /* Number of digits in symbolic data */
  int             off;                  /* Offset into the memory */
  int             off;                  /* Offset into the memory */
  unsigned int    errcode;
  unsigned int    errcode;
 
 
  if (2 != sscanf (buf->data, "M%x,%x:", &addr, &len))
  if (2 != sscanf (buf->data, "M%x,%x:", &addr, &len))
    {
    {
      fprintf (stderr, "Warning: Failed to recognize RSP write memory "
      fprintf (stderr, "Warning: Failed to recognize RSP write memory "
               "command: %s\n", buf->data);
               "command: %s\n", buf->data);
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
    }
    }
 
 
  /* Find the start of the data and check there is the amount we expect. */
  /* Find the start of the data and check there is the amount we expect. */
  symdat = memchr ((const void *)buf->data, ':', GDB_BUF_MAX) + 1;
  symdat = memchr ((const void *)buf->data, ':', GDB_BUF_MAX) + 1;
  datlen = buf->len - (symdat - buf->data);
  datlen = buf->len - (symdat - buf->data);
 
 
  /* Sanity check */
  /* Sanity check */
  if (len * 2 != datlen)
  if (len * 2 != datlen)
    {
    {
      fprintf (stderr, "Warning: Write of %d digits requested, but %d digits "
      fprintf (stderr, "Warning: Write of %d digits requested, but %d digits "
               "supplied: packet ignored\n", len * 2, datlen );
               "supplied: packet ignored\n", len * 2, datlen );
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
    }
    }
 
 
  /* Write the bytes to memory */
  /* Write the bytes to memory */
  // Put all the data into a single buffer, so it can be burst-written via JTAG.
  // Put all the data into a single buffer, so it can be burst-written via JTAG.
  // One burst is much faster than many single-byte transactions.
  // One burst is much faster than many single-byte transactions.
  unsigned char *tmpbuf = (unsigned char *) malloc(len);
  unsigned char *tmpbuf = (unsigned char *) malloc(len);
  for (off = 0; off < len; off++)
  for (off = 0; off < len; off++)
    {
    {
      unsigned char  nyb1 = hex (symdat[off * 2]);
      unsigned char  nyb1 = hex (symdat[off * 2]);
      unsigned char  nyb2 = hex (symdat[off * 2 + 1]);
      unsigned char  nyb2 = hex (symdat[off * 2 + 1]);
      tmpbuf[off] = (nyb1 << 4) | nyb2;
      tmpbuf[off] = (nyb1 << 4) | nyb2;
    }
    }
 
 
  errcode = dbg_wb_write_block8(addr, tmpbuf, len);
  errcode = dbg_wb_write_block8(addr, tmpbuf, len);
  free(tmpbuf);
  free(tmpbuf);
 
 
  /* Can't really check if the memory addresses are valid on hardware. */
  /* Can't really check if the memory addresses are valid on hardware. */
  if(errcode == APP_ERR_NONE) {
  if(errcode == APP_ERR_NONE) {
    put_str_packet ("OK");
    put_str_packet ("OK");
  }
  }
  else {
  else {
    fprintf(stderr, "Error writing memory: %s\n", get_err_string(errcode));
    fprintf(stderr, "Error writing memory: %s\n", get_err_string(errcode));
    put_str_packet("E01");
    put_str_packet("E01");
  }
  }
 
 
}       /* rsp_write_mem () */
}       /* rsp_write_mem () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Read a single register
/*!Read a single register
 
 
   The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
   The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
   (i.e. SPR NPC) and SR (i.e. SPR SR). The register is returned as a
   (i.e. SPR NPC) and SR (i.e. SPR SR). The register is returned as a
   sequence of bytes in target endian order.
   sequence of bytes in target endian order.
 
 
   Each byte is packed as a pair of hex digits.
   Each byte is packed as a pair of hex digits.
 
 
   @param[in] buf  The original packet request. Reused for the reply.        */
   @param[in] buf  The original packet request. Reused for the reply.        */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_read_reg (struct rsp_buf *buf)
rsp_read_reg (struct rsp_buf *buf)
{
{
  unsigned int  regnum;
  unsigned int  regnum;
  unsigned long tmp;
  unsigned long tmp;
  unsigned int errcode = APP_ERR_NONE;
  unsigned int errcode = APP_ERR_NONE;
 
 
  /* Break out the fields from the data */
  /* Break out the fields from the data */
  if (1 != sscanf (buf->data, "p%x", &regnum))
  if (1 != sscanf (buf->data, "p%x", &regnum))
    {
    {
      fprintf (stderr, "Warning: Failed to recognize RSP read register "
      fprintf (stderr, "Warning: Failed to recognize RSP read register "
               "command: \'%s\'\n", buf->data);
               "command: \'%s\'\n", buf->data);
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
    }
    }
 
 
  /* Get the relevant register */
  /* Get the relevant register */
  if (regnum < MAX_GPRS)
  if (regnum < MAX_GPRS)
    {
    {
      errcode = dbg_cpu0_read(SPR_GPR_BASE+regnum, &tmp);
      errcode = dbg_cpu0_read(SPR_GPR_BASE+regnum, &tmp);
    }
    }
  else if (PPC_REGNUM == regnum)
  else if (PPC_REGNUM == regnum)
    {
    {
      errcode = dbg_cpu0_read(SPR_PPC, &tmp);
      errcode = dbg_cpu0_read(SPR_PPC, &tmp);
    }
    }
  else if (NPC_REGNUM == regnum)
  else if (NPC_REGNUM == regnum)
    {
    {
      if(use_cached_npc) {
      if(use_cached_npc) {
        tmp = cached_npc;
        tmp = cached_npc;
      } else {
      } else {
        errcode = dbg_cpu0_read(SPR_NPC, &tmp);
        errcode = dbg_cpu0_read(SPR_NPC, &tmp);
      }
      }
    }
    }
  else if (SR_REGNUM == regnum)
  else if (SR_REGNUM == regnum)
    {
    {
      errcode = dbg_cpu0_read(SPR_SR, &tmp);
      errcode = dbg_cpu0_read(SPR_SR, &tmp);
    }
    }
  else
  else
    {
    {
      /* Error response if we don't know the register */
      /* Error response if we don't know the register */
      fprintf (stderr, "Warning: Attempt to read unknown register 0x%x: "
      fprintf (stderr, "Warning: Attempt to read unknown register 0x%x: "
               "ignored\n", regnum);
               "ignored\n", regnum);
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
    }
    }
 
 
  if(errcode == APP_ERR_NONE) {
  if(errcode == APP_ERR_NONE) {
    reg2hex(tmp, buf->data);
    reg2hex(tmp, buf->data);
    buf->len = strlen (buf->data);
    buf->len = strlen (buf->data);
    put_packet (buf);
    put_packet (buf);
  }
  }
  else {
  else {
    fprintf(stderr, "Error reading register: %s\n", get_err_string(errcode));
    fprintf(stderr, "Error reading register: %s\n", get_err_string(errcode));
    put_str_packet("E01");
    put_str_packet("E01");
  }
  }
 
 
}       /* rsp_read_reg () */
}       /* rsp_read_reg () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Write a single register
/*!Write a single register
 
 
   The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
   The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
   (i.e. SPR NPC) and SR (i.e. SPR SR). The register is specified as a
   (i.e. SPR NPC) and SR (i.e. SPR SR). The register is specified as a
   sequence of bytes in target endian order.
   sequence of bytes in target endian order.
 
 
   Each byte is packed as a pair of hex digits.
   Each byte is packed as a pair of hex digits.
 
 
   @param[in] buf  The original packet request.                              */
   @param[in] buf  The original packet request.                              */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_write_reg (struct rsp_buf *buf)
rsp_write_reg (struct rsp_buf *buf)
{
{
  unsigned int  regnum;
  unsigned int  regnum;
  char          valstr[9];              /* Allow for EOS on the string */
  char          valstr[9];              /* Allow for EOS on the string */
  unsigned int  errcode = APP_ERR_NONE;
  unsigned int  errcode = APP_ERR_NONE;
 
 
  /* Break out the fields from the data */
  /* Break out the fields from the data */
  if (2 != sscanf (buf->data, "P%x=%8s", &regnum, valstr))
  if (2 != sscanf (buf->data, "P%x=%8s", &regnum, valstr))
    {
    {
      fprintf (stderr, "Warning: Failed to recognize RSP write register "
      fprintf (stderr, "Warning: Failed to recognize RSP write register "
               "command: %s\n", buf->data);
               "command: %s\n", buf->data);
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
    }
    }
 
 
  /* Set the relevant register.  Must translate between GDB register numbering and hardware reg. numbers. */
  /* Set the relevant register.  Must translate between GDB register numbering and hardware reg. numbers. */
  if (regnum < MAX_GPRS)
  if (regnum < MAX_GPRS)
    {
    {
      errcode = dbg_cpu0_write(SPR_GPR_BASE+regnum, hex2reg(valstr));
      errcode = dbg_cpu0_write(SPR_GPR_BASE+regnum, hex2reg(valstr));
    }
    }
  else if (PPC_REGNUM == regnum)
  else if (PPC_REGNUM == regnum)
    {
    {
      errcode = dbg_cpu0_write(SPR_PPC, hex2reg(valstr));
      errcode = dbg_cpu0_write(SPR_PPC, hex2reg(valstr));
    }
    }
  else if (NPC_REGNUM == regnum)
  else if (NPC_REGNUM == regnum)
    {
    {
      errcode = set_npc (hex2reg (valstr));
      errcode = set_npc (hex2reg (valstr));
    }
    }
  else if (SR_REGNUM == regnum)
  else if (SR_REGNUM == regnum)
    {
    {
      errcode = dbg_cpu0_write(SPR_SR, hex2reg(valstr));
      errcode = dbg_cpu0_write(SPR_SR, hex2reg(valstr));
    }
    }
  else
  else
    {
    {
      /* Error response if we don't know the register */
      /* Error response if we don't know the register */
      fprintf (stderr, "Warning: Attempt to write unknown register 0x%x: "
      fprintf (stderr, "Warning: Attempt to write unknown register 0x%x: "
               "ignored\n", regnum);
               "ignored\n", regnum);
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
    }
    }
 
 
  if(errcode == APP_ERR_NONE) {
  if(errcode == APP_ERR_NONE) {
    put_str_packet ("OK");
    put_str_packet ("OK");
  }
  }
  else {
  else {
    fprintf(stderr, "Error writing register: %s\n", get_err_string(errcode));
    fprintf(stderr, "Error writing register: %s\n", get_err_string(errcode));
    put_str_packet("E01");
    put_str_packet("E01");
  }
  }
 
 
}       /* rsp_write_reg () */
}       /* rsp_write_reg () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP query request
/*!Handle a RSP query request
 
 
   @param[in] buf  The request                                               */
   @param[in] buf  The request                                               */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_query (struct rsp_buf *buf)
rsp_query (struct rsp_buf *buf)
{
{
  if (0 == strcmp ("qC", buf->data))
  if (0 == strcmp ("qC", buf->data))
    {
    {
      /* Return the current thread ID (unsigned hex). A null response
      /* Return the current thread ID (unsigned hex). A null response
         indicates to use the previously selected thread. Since we do not
         indicates to use the previously selected thread. Since we do not
         support a thread concept, this is the appropriate response. */
         support a thread concept, this is the appropriate response. */
      put_str_packet ("");
      put_str_packet ("");
    }
    }
  else if (0 == strncmp ("qCRC", buf->data, strlen ("qCRC")))
  else if (0 == strncmp ("qCRC", buf->data, strlen ("qCRC")))
    {
    {
      /* Return CRC of memory area */
      /* Return CRC of memory area */
      fprintf (stderr, "Warning: RSP CRC query not supported\n");
      fprintf (stderr, "Warning: RSP CRC query not supported\n");
      put_str_packet ("E01");
      put_str_packet ("E01");
    }
    }
  else if (0 == strcmp ("qfThreadInfo", buf->data))
  else if (0 == strcmp ("qfThreadInfo", buf->data))
    {
    {
      /* Return info about active threads. We return just '-1' */
      /* Return info about active threads. We return just '-1' */
      put_str_packet ("m-1");
      put_str_packet ("m-1");
    }
    }
  else if (0 == strcmp ("qsThreadInfo", buf->data))
  else if (0 == strcmp ("qsThreadInfo", buf->data))
    {
    {
      /* Return info about more active threads. We have no more, so return the
      /* Return info about more active threads. We have no more, so return the
         end of list marker, 'l' */
         end of list marker, 'l' */
      put_str_packet ("l");
      put_str_packet ("l");
    }
    }
  else if (0 == strncmp ("qGetTLSAddr:", buf->data, strlen ("qGetTLSAddr:")))
  else if (0 == strncmp ("qGetTLSAddr:", buf->data, strlen ("qGetTLSAddr:")))
    {
    {
      /* We don't support this feature */
      /* We don't support this feature */
      put_str_packet ("");
      put_str_packet ("");
    }
    }
  else if (0 == strncmp ("qL", buf->data, strlen ("qL")))
  else if (0 == strncmp ("qL", buf->data, strlen ("qL")))
    {
    {
      /* Deprecated and replaced by 'qfThreadInfo' */
      /* Deprecated and replaced by 'qfThreadInfo' */
      fprintf (stderr, "Warning: RSP qL deprecated: no info returned\n");
      fprintf (stderr, "Warning: RSP qL deprecated: no info returned\n");
      put_str_packet ("qM001");
      put_str_packet ("qM001");
    }
    }
  else if (0 == strcmp ("qOffsets", buf->data))
  else if (0 == strcmp ("qOffsets", buf->data))
    {
    {
      /* Report any relocation */
      /* Report any relocation */
      put_str_packet ("Text=0;Data=0;Bss=0");
      put_str_packet ("Text=0;Data=0;Bss=0");
    }
    }
  else if (0 == strncmp ("qP", buf->data, strlen ("qP")))
  else if (0 == strncmp ("qP", buf->data, strlen ("qP")))
    {
    {
      /* Deprecated and replaced by 'qThreadExtraInfo' */
      /* Deprecated and replaced by 'qThreadExtraInfo' */
      fprintf (stderr, "Warning: RSP qP deprecated: no info returned\n");
      fprintf (stderr, "Warning: RSP qP deprecated: no info returned\n");
      put_str_packet ("");
      put_str_packet ("");
    }
    }
  else if (0 == strncmp ("qRcmd,", buf->data, strlen ("qRcmd,")))
  else if (0 == strncmp ("qRcmd,", buf->data, strlen ("qRcmd,")))
    {
    {
      /* This is used to interface to commands to do "stuff" */
      /* This is used to interface to commands to do "stuff" */
      rsp_command (buf);
      rsp_command (buf);
    }
    }
  else if (0 == strncmp ("qSupported", buf->data, strlen ("qSupported")))
  else if (0 == strncmp ("qSupported", buf->data, strlen ("qSupported")))
    {
    {
      /* Report a list of the features we support. For now we just ignore any
      /* Report a list of the features we support. For now we just ignore any
         supplied specific feature queries, but in the future these may be
         supplied specific feature queries, but in the future these may be
         supported as well. Note that the packet size allows for 'G' + all the
         supported as well. Note that the packet size allows for 'G' + all the
         registers sent to us, or a reply to 'g' with all the registers and an
         registers sent to us, or a reply to 'g' with all the registers and an
         EOS so the buffer is a well formed string. */
         EOS so the buffer is a well formed string. */
 
 
      char  reply[GDB_BUF_MAX];
      char  reply[GDB_BUF_MAX];
 
 
      sprintf (reply, "PacketSize=%x", GDB_BUF_MAX);
      sprintf (reply, "PacketSize=%x", GDB_BUF_MAX);
      put_str_packet (reply);
      put_str_packet (reply);
    }
    }
  else if (0 == strncmp ("qSymbol:", buf->data, strlen ("qSymbol:")))
  else if (0 == strncmp ("qSymbol:", buf->data, strlen ("qSymbol:")))
    {
    {
      /* Offer to look up symbols. Nothing we want (for now). TODO. This just
      /* Offer to look up symbols. Nothing we want (for now). TODO. This just
         ignores any replies to symbols we looked up, but we didn't want to
         ignores any replies to symbols we looked up, but we didn't want to
         do that anyway! */
         do that anyway! */
      put_str_packet ("OK");
      put_str_packet ("OK");
    }
    }
  else if (0 == strncmp ("qThreadExtraInfo,", buf->data,
  else if (0 == strncmp ("qThreadExtraInfo,", buf->data,
                         strlen ("qThreadExtraInfo,")))
                         strlen ("qThreadExtraInfo,")))
    {
    {
      /* Report that we are runnable, but the text must be hex ASCI
      /* Report that we are runnable, but the text must be hex ASCI
         digits. For now do this by steam, reusing the original packet */
         digits. For now do this by steam, reusing the original packet */
      sprintf (buf->data, "%02x%02x%02x%02x%02x%02x%02x%02x%02x",
      sprintf (buf->data, "%02x%02x%02x%02x%02x%02x%02x%02x%02x",
               'R', 'u', 'n', 'n', 'a', 'b', 'l', 'e', 0);
               'R', 'u', 'n', 'n', 'a', 'b', 'l', 'e', 0);
      buf->len = strlen (buf->data);
      buf->len = strlen (buf->data);
      put_packet (buf);
      put_packet (buf);
    }
    }
  else if (0 == strncmp ("qXfer:", buf->data, strlen ("qXfer:")))
  else if (0 == strncmp ("qXfer:", buf->data, strlen ("qXfer:")))
    {
    {
      /* For now we support no 'qXfer' requests, but these should not be
      /* For now we support no 'qXfer' requests, but these should not be
         expected, since they were not reported by 'qSupported' */
         expected, since they were not reported by 'qSupported' */
      fprintf (stderr, "Warning: RSP 'qXfer' not supported: ignored\n");
      fprintf (stderr, "Warning: RSP 'qXfer' not supported: ignored\n");
      put_str_packet ("");
      put_str_packet ("");
    }
    }
  else
  else
    {
    {
      fprintf (stderr, "Unrecognized RSP query: ignored\n");
      fprintf (stderr, "Unrecognized RSP query: ignored\n");
    }
    }
}       /* rsp_query () */
}       /* rsp_query () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP qRcmd request
/*!Handle a RSP qRcmd request
 
 
  The actual command follows the "qRcmd," in ASCII encoded to hex
  The actual command follows the "qRcmd," in ASCII encoded to hex
 
 
   @param[in] buf  The request in full                                       */
   @param[in] buf  The request in full                                       */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_command (struct rsp_buf *buf)
rsp_command (struct rsp_buf *buf)
{
{
  char  cmd[GDB_BUF_MAX];
  char  cmd[GDB_BUF_MAX];
  unsigned long tmp;
  unsigned long tmp;
 
 
  hex2ascii (cmd, &(buf->data[strlen ("qRcmd,")]));
  hex2ascii (cmd, &(buf->data[strlen ("qRcmd,")]));
 
 
  /* Work out which command it is */
  /* Work out which command it is */
  if (0 == strncmp ("readspr ", cmd, strlen ("readspr")))
  if (0 == strncmp ("readspr ", cmd, strlen ("readspr")))
    {
    {
      unsigned int       regno;
      unsigned int       regno;
 
 
      /* Parse and return error if we fail */
      /* Parse and return error if we fail */
      if( 1 != sscanf (cmd, "readspr %4x", &regno))
      if( 1 != sscanf (cmd, "readspr %4x", &regno))
        {
        {
          fprintf (stderr, "Warning: qRcmd %s not recognized: ignored\n",
          fprintf (stderr, "Warning: qRcmd %s not recognized: ignored\n",
                   cmd);
                   cmd);
          put_str_packet ("E01");
          put_str_packet ("E01");
          return;
          return;
        }
        }
 
 
      /* SPR out of range */
      /* SPR out of range */
      if (regno > MAX_SPRS)
      if (regno > MAX_SPRS)
        {
        {
          fprintf (stderr, "Warning: qRcmd readspr %x too large: ignored\n",
          fprintf (stderr, "Warning: qRcmd readspr %x too large: ignored\n",
                   regno);
                   regno);
          put_str_packet ("E01");
          put_str_packet ("E01");
          return;
          return;
        }
        }
 
 
      /* Construct the reply */
      /* Construct the reply */
      dbg_cpu0_read(regno, &tmp);  // TODO Check return value of all hardware accesses
      dbg_cpu0_read(regno, &tmp);  // TODO Check return value of all hardware accesses
      sprintf (cmd, "%8lx", tmp);
      sprintf (cmd, "%8lx", tmp);
      ascii2hex (buf->data, cmd);
      ascii2hex (buf->data, cmd);
      buf->len = strlen (buf->data);
      buf->len = strlen (buf->data);
      put_packet (buf);
      put_packet (buf);
    }
    }
  else if (0 == strncmp ("writespr ", cmd, strlen ("writespr")))
  else if (0 == strncmp ("writespr ", cmd, strlen ("writespr")))
    {
    {
      unsigned int       regno;
      unsigned int       regno;
      unsigned long int  val;
      unsigned long int  val;
 
 
      /* Parse and return error if we fail */
      /* Parse and return error if we fail */
      if( 2 != sscanf (cmd, "writespr %4x %8lx", &regno, &val))
      if( 2 != sscanf (cmd, "writespr %4x %8lx", &regno, &val))
        {
        {
          fprintf (stderr, "Warning: qRcmd %s not recognized: ignored\n",
          fprintf (stderr, "Warning: qRcmd %s not recognized: ignored\n",
                   cmd);
                   cmd);
          put_str_packet ("E01");
          put_str_packet ("E01");
          return;
          return;
        }
        }
 
 
      /* SPR out of range */
      /* SPR out of range */
      if (regno > MAX_SPRS)
      if (regno > MAX_SPRS)
        {
        {
          fprintf (stderr, "Warning: qRcmd writespr %x too large: ignored\n",
          fprintf (stderr, "Warning: qRcmd writespr %x too large: ignored\n",
                   regno);
                   regno);
          put_str_packet ("E01");
          put_str_packet ("E01");
          return;
          return;
        }
        }
 
 
      /* Update the SPR and reply "OK" */
      /* Update the SPR and reply "OK" */
      dbg_cpu0_write(regno, val);
      dbg_cpu0_write(regno, val);
      put_str_packet ("OK");
      put_str_packet ("OK");
    }
    }
 
 
}       /* rsp_command () */
}       /* rsp_command () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP set request
/*!Handle a RSP set request
 
 
   @param[in] buf  The request                                               */
   @param[in] buf  The request                                               */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_set (struct rsp_buf *buf)
rsp_set (struct rsp_buf *buf)
{
{
  if (0 == strncmp ("QPassSignals:", buf->data, strlen ("QPassSignals:")))
  if (0 == strncmp ("QPassSignals:", buf->data, strlen ("QPassSignals:")))
    {
    {
      /* Passing signals not supported */
      /* Passing signals not supported */
      put_str_packet ("");
      put_str_packet ("");
    }
    }
  else if ((0 == strncmp ("QTDP",    buf->data, strlen ("QTDP")))   ||
  else if ((0 == strncmp ("QTDP",    buf->data, strlen ("QTDP")))   ||
           (0 == strncmp ("QFrame",  buf->data, strlen ("QFrame"))) ||
           (0 == strncmp ("QFrame",  buf->data, strlen ("QFrame"))) ||
           (0 == strcmp  ("QTStart", buf->data))                    ||
           (0 == strcmp  ("QTStart", buf->data))                    ||
           (0 == strcmp  ("QTStop",  buf->data))                    ||
           (0 == strcmp  ("QTStop",  buf->data))                    ||
           (0 == strcmp  ("QTinit",  buf->data))                    ||
           (0 == strcmp  ("QTinit",  buf->data))                    ||
           (0 == strncmp ("QTro",    buf->data, strlen ("QTro"))))
           (0 == strncmp ("QTro",    buf->data, strlen ("QTro"))))
    {
    {
      /* All tracepoint features are not supported. This reply is really only
      /* All tracepoint features are not supported. This reply is really only
         needed to 'QTDP', since with that the others should not be
         needed to 'QTDP', since with that the others should not be
         generated. */
         generated. */
      put_str_packet ("");
      put_str_packet ("");
    }
    }
  else
  else
    {
    {
      fprintf (stderr, "Unrecognized RSP set request: ignored\n");
      fprintf (stderr, "Unrecognized RSP set request: ignored\n");
    }
    }
}       /* rsp_set () */
}       /* rsp_set () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP restart request
/*!Handle a RSP restart request
 
 
   For now we just put the program counter back to the one used with the last
   For now we just put the program counter back to the one used with the last
   vRun request.                                                             */
   vRun request.                                                             */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_restart ()
rsp_restart ()
{
{
  set_npc (rsp.start_addr);
  set_npc (rsp.start_addr);
 
 
}       /* rsp_restart () */
}       /* rsp_restart () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP step request
/*!Handle a RSP step request
 
 
   Parse the command to see if there is an address. Uses the underlying
   Parse the command to see if there is an address. Uses the underlying
   generic step function, with EXCEPT_NONE.
   generic step function, with EXCEPT_NONE.
 
 
   @param[in] buf  The full step packet                          */
   @param[in] buf  The full step packet                          */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_step (struct rsp_buf *buf)
rsp_step (struct rsp_buf *buf)
{
{
  unsigned long int  addr;              /* The address to step from, if any */
  unsigned long int  addr;              /* The address to step from, if any */
 
 
  if(strncmp(buf->data, "s", 2))
  if(strncmp(buf->data, "s", 2))
    {
    {
      if(1 != sscanf (buf->data, "s%lx", &addr))
      if(1 != sscanf (buf->data, "s%lx", &addr))
        {
        {
          fprintf (stderr,
          fprintf (stderr,
                   "Warning: RSP step address %s not recognized: ignored\n",
                   "Warning: RSP step address %s not recognized: ignored\n",
                   buf->data);
                   buf->data);
        }
        }
      else
      else
        {
        {
          /* Set the address as the value of the next program counter */
          /* Set the address as the value of the next program counter */
          // TODO  Is implementing this really just this simple?
          // TODO  Is implementing this really just this simple?
          //set_npc (addr);
          //set_npc (addr);
        }
        }
    }
    }
 
 
  rsp_step_generic (EXCEPT_NONE);
  rsp_step_generic (EXCEPT_NONE);
 
 
}       /* rsp_step () */
}       /* rsp_step () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP step with signal request
/*!Handle a RSP step with signal request
 
 
   Currently null. Will use the underlying generic step function.
   Currently null. Will use the underlying generic step function.
 
 
   @param[in] buf  The full step with signal packet              */
   @param[in] buf  The full step with signal packet              */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_step_with_signal (struct rsp_buf *buf)
rsp_step_with_signal (struct rsp_buf *buf)
{
{
  int val;
  int val;
  printf ("RSP step with signal '%s' received\n", buf->data);
  printf ("RSP step with signal '%s' received\n", buf->data);
  val = strtoul(&buf->data[1], NULL, 10);
  val = strtoul(&buf->data[1], NULL, 10);
  rsp_step_generic(val);
  rsp_step_generic(val);
}       /* rsp_step_with_signal () */
}       /* rsp_step_with_signal () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Generic processing of a step request
/*!Generic processing of a step request
 
 
   The signal may be EXCEPT_NONE if there is no exception to be
   The signal may be EXCEPT_NONE if there is no exception to be
   handled. Currently the exception is ignored.
   handled. Currently the exception is ignored.
 
 
   The single step flag is set in the debug registers and then the processor
   The single step flag is set in the debug registers and then the processor
   is unstalled.
   is unstalled.
 
 
   @param[in] addr    Address from which to step
   @param[in] addr    Address from which to step
   @param[in] except  The exception to use (if any)                          */
   @param[in] except  The exception to use (if any)                          */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_step_generic (unsigned long int  except)
rsp_step_generic (unsigned long int  except)
{
{
  unsigned long tmp;
  unsigned long tmp;
 
 
  /* Clear Debug Reason Register and watchpoint break generation in Debug Mode
  /* Clear Debug Reason Register and watchpoint break generation in Debug Mode
     Register 2 */
     Register 2 */
  tmp = 0;
  tmp = 0;
  dbg_cpu0_write(SPR_DRR, tmp);  // *** TODO Check return value of all hardware accesses
  dbg_cpu0_write(SPR_DRR, tmp);  // *** TODO Check return value of all hardware accesses
  dbg_cpu0_read(SPR_DMR2, &tmp);
  dbg_cpu0_read(SPR_DMR2, &tmp);
  if(tmp & SPR_DMR2_WGB) {
  if(tmp & SPR_DMR2_WGB) {
    tmp &= ~SPR_DMR2_WGB;
    tmp &= ~SPR_DMR2_WGB;
    dbg_cpu0_write(SPR_DMR2, tmp);
    dbg_cpu0_write(SPR_DMR2, tmp);
  }
  }
 
 
  /* Set the single step trigger in Debug Mode Register 1 and set traps to be
  /* Set the single step trigger in Debug Mode Register 1 and set traps to be
     handled by the debug unit in the Debug Stop Register */
     handled by the debug unit in the Debug Stop Register */
  if(!rsp.single_step_mode)
  if(!rsp.single_step_mode)
    {
    {
      dbg_cpu0_read(SPR_DMR1, &tmp);
      dbg_cpu0_read(SPR_DMR1, &tmp);
      tmp |= SPR_DMR1_ST|SPR_DMR1_BT;
      tmp |= SPR_DMR1_ST|SPR_DMR1_BT;
      dbg_cpu0_write(SPR_DMR1, tmp);
      dbg_cpu0_write(SPR_DMR1, tmp);
      dbg_cpu0_read(SPR_DSR, &tmp);
      dbg_cpu0_read(SPR_DSR, &tmp);
      if(!(tmp & SPR_DSR_TE)) {
      if(!(tmp & SPR_DSR_TE)) {
        tmp |= SPR_DSR_TE;
        tmp |= SPR_DSR_TE;
        dbg_cpu0_write(SPR_DSR, tmp);
        dbg_cpu0_write(SPR_DSR, tmp);
      }
      }
      rsp.single_step_mode = 1;
      rsp.single_step_mode = 1;
    }
    }
 
 
  /* Unstall the processor */
  /* Unstall the processor */
  set_stall_state (0);
  set_stall_state (0);
 
 
  /* Note the GDB client is now waiting for a reply. */
  /* Note the GDB client is now waiting for a reply. */
  rsp.client_waiting = 1;
  rsp.client_waiting = 1;
 
 
}       /* rsp_step_generic () */
}       /* rsp_step_generic () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP 'v' packet
/*!Handle a RSP 'v' packet
 
 
   These are commands associated with executing the code on the target
   These are commands associated with executing the code on the target
 
 
   @param[in] buf  The request                                               */
   @param[in] buf  The request                                               */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_vpkt (struct rsp_buf *buf)
rsp_vpkt (struct rsp_buf *buf)
{
{
  if (0 == strncmp ("vAttach;", buf->data, strlen ("vAttach;")))
  if (0 == strncmp ("vAttach;", buf->data, strlen ("vAttach;")))
    {
    {
      /* Attaching is a null action, since we have no other process. We just
      /* Attaching is a null action, since we have no other process. We just
         return a stop packet (using TRAP) to indicate we are stopped. */
         return a stop packet (using TRAP) to indicate we are stopped. */
      put_str_packet ("S05");
      put_str_packet ("S05");
      return;
      return;
    }
    }
  else if (0 == strcmp ("vCont?", buf->data))
  else if (0 == strcmp ("vCont?", buf->data))
    {
    {
      /* For now we don't support this. */
      /* For now we don't support this. */
      put_str_packet ("");
      put_str_packet ("");
      return;
      return;
    }
    }
  else if (0 == strncmp ("vCont", buf->data, strlen ("vCont")))
  else if (0 == strncmp ("vCont", buf->data, strlen ("vCont")))
    {
    {
      /* This shouldn't happen, because we've reported non-support via vCont?
      /* This shouldn't happen, because we've reported non-support via vCont?
         above */
         above */
      fprintf (stderr, "Warning: RSP vCont not supported: ignored\n" );
      fprintf (stderr, "Warning: RSP vCont not supported: ignored\n" );
      return;
      return;
    }
    }
  else if (0 == strncmp ("vFile:", buf->data, strlen ("vFile:")))
  else if (0 == strncmp ("vFile:", buf->data, strlen ("vFile:")))
    {
    {
      /* For now we don't support this. */
      /* For now we don't support this. */
      fprintf (stderr, "Warning: RSP vFile not supported: ignored\n" );
      fprintf (stderr, "Warning: RSP vFile not supported: ignored\n" );
      put_str_packet ("");
      put_str_packet ("");
      return;
      return;
    }
    }
  else if (0 == strncmp ("vFlashErase:", buf->data, strlen ("vFlashErase:")))
  else if (0 == strncmp ("vFlashErase:", buf->data, strlen ("vFlashErase:")))
    {
    {
      /* For now we don't support this. */
      /* For now we don't support this. */
      fprintf (stderr, "Warning: RSP vFlashErase not supported: ignored\n" );
      fprintf (stderr, "Warning: RSP vFlashErase not supported: ignored\n" );
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
    }
    }
  else if (0 == strncmp ("vFlashWrite:", buf->data, strlen ("vFlashWrite:")))
  else if (0 == strncmp ("vFlashWrite:", buf->data, strlen ("vFlashWrite:")))
    {
    {
      /* For now we don't support this. */
      /* For now we don't support this. */
      fprintf (stderr, "Warning: RSP vFlashWrite not supported: ignored\n" );
      fprintf (stderr, "Warning: RSP vFlashWrite not supported: ignored\n" );
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
    }
    }
  else if (0 == strcmp ("vFlashDone", buf->data))
  else if (0 == strcmp ("vFlashDone", buf->data))
    {
    {
      /* For now we don't support this. */
      /* For now we don't support this. */
      fprintf (stderr, "Warning: RSP vFlashDone not supported: ignored\n" );
      fprintf (stderr, "Warning: RSP vFlashDone not supported: ignored\n" );
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
    }
    }
  else if (0 == strncmp ("vRun;", buf->data, strlen ("vRun;")))
  else if (0 == strncmp ("vRun;", buf->data, strlen ("vRun;")))
    {
    {
      /* We shouldn't be given any args, but check for this */
      /* We shouldn't be given any args, but check for this */
      if (buf->len > strlen ("vRun;"))
      if (buf->len > strlen ("vRun;"))
        {
        {
          fprintf (stderr, "Warning: Unexpected arguments to RSP vRun "
          fprintf (stderr, "Warning: Unexpected arguments to RSP vRun "
                   "command: ignored\n");
                   "command: ignored\n");
        }
        }
 
 
      /* Restart the current program. However unlike a "R" packet, "vRun"
      /* Restart the current program. However unlike a "R" packet, "vRun"
         should behave as though it has just stopped. We use signal
         should behave as though it has just stopped. We use signal
         5 (TRAP). */
         5 (TRAP). */
      rsp_restart ();
      rsp_restart ();
      put_str_packet ("S05");
      put_str_packet ("S05");
    }
    }
  else
  else
    {
    {
      fprintf (stderr, "Warning: Unknown RSP 'v' packet type %s: ignored\n",
      fprintf (stderr, "Warning: Unknown RSP 'v' packet type %s: ignored\n",
               buf->data);
               buf->data);
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
    }
    }
}       /* rsp_vpkt () */
}       /* rsp_vpkt () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP write memory (binary) request
/*!Handle a RSP write memory (binary) request
 
 
   Syntax is:
   Syntax is:
 
 
     X<addr>,<length>:
     X<addr>,<length>:
 
 
   Followed by the specified number of bytes as raw binary. Response should be
   Followed by the specified number of bytes as raw binary. Response should be
   "OK" if all copied OK, E<nn> if error <nn> has occurred.
   "OK" if all copied OK, E<nn> if error <nn> has occurred.
 
 
   The length given is the number of bytes to be written. However the number
   The length given is the number of bytes to be written. However the number
   of data bytes may be greater, since '#', '$' and '}' are escaped by
   of data bytes may be greater, since '#', '$' and '}' are escaped by
   preceding them by '}' and oring with 0x20.
   preceding them by '}' and oring with 0x20.
 
 
   @param[in] buf  The command received                                      */
   @param[in] buf  The command received                                      */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_write_mem_bin (struct rsp_buf *buf)
rsp_write_mem_bin (struct rsp_buf *buf)
{
{
  unsigned int  addr;                   /* Where to write the memory */
  unsigned int  addr;                   /* Where to write the memory */
  int           len;                    /* Number of bytes to write */
  int           len;                    /* Number of bytes to write */
  char         *bindat;                 /* Pointer to the binary data */
  char         *bindat;                 /* Pointer to the binary data */
  int           off;                    /* Offset to start of binary data */
  int           off;                    /* Offset to start of binary data */
  int           newlen;                 /* Number of bytes in bin data */
  int           newlen;                 /* Number of bytes in bin data */
  unsigned int  errcode;
  unsigned int  errcode;
 
 
  if (2 != sscanf (buf->data, "X%x,%x:", &addr, &len))
  if (2 != sscanf (buf->data, "X%x,%x:", &addr, &len))
    {
    {
      fprintf (stderr, "Warning: Failed to recognize RSP write memory "
      fprintf (stderr, "Warning: Failed to recognize RSP write memory "
               "command: %s\n", buf->data);
               "command: %s\n", buf->data);
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
    }
    }
 
 
  /* Find the start of the data and "unescape" it */
  /* Find the start of the data and "unescape" it */
  bindat = memchr ((const void *)buf->data, ':', GDB_BUF_MAX) + 1;
  bindat = memchr ((const void *)buf->data, ':', GDB_BUF_MAX) + 1;
  off    = bindat - buf->data;
  off    = bindat - buf->data;
  newlen = rsp_unescape (bindat, buf->len - off);
  newlen = rsp_unescape (bindat, buf->len - off);
 
 
  /* Sanity check */
  /* Sanity check */
  if (newlen != len)
  if (newlen != len)
    {
    {
      int  minlen = len < newlen ? len : newlen;
      int  minlen = len < newlen ? len : newlen;
 
 
      fprintf (stderr, "Warning: Write of %d bytes requested, but %d bytes "
      fprintf (stderr, "Warning: Write of %d bytes requested, but %d bytes "
               "supplied. %d will be written\n", len, newlen, minlen);
               "supplied. %d will be written\n", len, newlen, minlen);
      len = minlen;
      len = minlen;
    }
    }
 
 
  /* Write the bytes to memory */
  /* Write the bytes to memory */
  errcode = dbg_wb_write_block8(addr, bindat, len);
  errcode = dbg_wb_write_block8(addr, (uint8_t *) bindat, len);
 
 
  // We can't really verify if the memory target address exists or not.
  // We can't really verify if the memory target address exists or not.
  // Don't write to non-existant memory unless your system wishbone implementation
  // Don't write to non-existant memory unless your system wishbone implementation
  // has a hardware bus timeout.
  // has a hardware bus timeout.
  if(errcode == APP_ERR_NONE) {
  if(errcode == APP_ERR_NONE) {
    put_str_packet ("OK");
    put_str_packet ("OK");
  }
  }
  else {
  else {
    fprintf(stderr, "Error writing memory: %s\n", get_err_string(errcode));
    fprintf(stderr, "Error writing memory: %s\n", get_err_string(errcode));
    put_str_packet("E01");
    put_str_packet("E01");
  }
  }
 
 
}       /* rsp_write_mem_bin () */
}       /* rsp_write_mem_bin () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP remove breakpoint or matchpoint request
/*!Handle a RSP remove breakpoint or matchpoint request
 
 
   For now only memory breakpoints are implemented, which are implemented by
   For now only memory breakpoints are implemented, which are implemented by
   substituting a breakpoint at the specified address. The implementation must
   substituting a breakpoint at the specified address. The implementation must
   cope with the possibility of duplicate packets.
   cope with the possibility of duplicate packets.
 
 
   @todo This doesn't work with icache/immu yet
   @todo This doesn't work with icache/immu yet
 
 
   @param[in] buf  The command received                                      */
   @param[in] buf  The command received                                      */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_remove_matchpoint (struct rsp_buf *buf)
rsp_remove_matchpoint (struct rsp_buf *buf)
{
{
  enum mp_type       type;              /* What sort of matchpoint */
  enum mp_type       type;              /* What sort of matchpoint */
  unsigned long int  addr;              /* Address specified */
  unsigned long int  addr;              /* Address specified */
  int                len;               /* Matchpoint length (not used) */
  int                len;               /* Matchpoint length (not used) */
  struct mp_entry   *mpe;               /* Info about the replaced instr */
  struct mp_entry   *mpe;               /* Info about the replaced instr */
  unsigned long instbuf[1];
  unsigned long instbuf[1];
 
 
  /* Break out the instruction */
  /* Break out the instruction */
  if (3 != sscanf (buf->data, "z%1d,%lx,%1d", (int *)&type, &addr, &len))
  if (3 != sscanf (buf->data, "z%1d,%lx,%1d", (int *)&type, &addr, &len))
    {
    {
      fprintf (stderr, "Warning: RSP matchpoint deletion request not "
      fprintf (stderr, "Warning: RSP matchpoint deletion request not "
               "recognized: ignored\n");
               "recognized: ignored\n");
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
    }
    }
 
 
  /* Sanity check that the length is 4 */
  /* Sanity check that the length is 4 */
  if (4 != len)
  if (4 != len)
    {
    {
      fprintf (stderr, "Warning: RSP matchpoint deletion length %d not "
      fprintf (stderr, "Warning: RSP matchpoint deletion length %d not "
               "valid: 4 assumed\n", len);
               "valid: 4 assumed\n", len);
      len = 4;
      len = 4;
    }
    }
 
 
  /* Sort out the type of matchpoint */
  /* Sort out the type of matchpoint */
  switch (type)
  switch (type)
    {
    {
    case BP_MEMORY:
    case BP_MEMORY:
      /* Memory breakpoint - replace the original instruction. */
      /* Memory breakpoint - replace the original instruction. */
      mpe = mp_hash_delete (type, addr);
      mpe = mp_hash_delete (type, addr);
 
 
      /* If the BP hasn't yet been deleted, put the original instruction
      /* If the BP hasn't yet been deleted, put the original instruction
         back. Don't forget to free the hash table entry afterwards. */
         back. Don't forget to free the hash table entry afterwards. */
      if (NULL != mpe)
      if (NULL != mpe)
        {
        {
          instbuf[0] = mpe->instr;
          instbuf[0] = mpe->instr;
          dbg_wb_write_block32(addr, instbuf, 1);  // *** TODO Check return value
          dbg_wb_write_block32(addr, instbuf, 1);  // *** TODO Check return value
          free (mpe);
          free (mpe);
        }
        }
 
 
      put_str_packet ("OK");
      put_str_packet ("OK");
 
 
      return;
      return;
 
 
    case BP_HARDWARE:
    case BP_HARDWARE:
      put_str_packet ("");              /* Not supported */
      put_str_packet ("");              /* Not supported */
      return;
      return;
 
 
    case WP_WRITE:
    case WP_WRITE:
      put_str_packet ("");              /* Not supported */
      put_str_packet ("");              /* Not supported */
      return;
      return;
 
 
    case WP_READ:
    case WP_READ:
      put_str_packet ("");              /* Not supported */
      put_str_packet ("");              /* Not supported */
      return;
      return;
 
 
    case WP_ACCESS:
    case WP_ACCESS:
      put_str_packet ("");              /* Not supported */
      put_str_packet ("");              /* Not supported */
      return;
      return;
 
 
    default:
    default:
      fprintf (stderr, "Warning: RSP matchpoint type %d not "
      fprintf (stderr, "Warning: RSP matchpoint type %d not "
               "recognized: ignored\n", type);
               "recognized: ignored\n", type);
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
 
 
    }
    }
}       /* rsp_remove_matchpoint () */
}       /* rsp_remove_matchpoint () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Handle a RSP insert breakpoint or matchpoint request
/*!Handle a RSP insert breakpoint or matchpoint request
 
 
   For now only memory breakpoints are implemented, which are implemented by
   For now only memory breakpoints are implemented, which are implemented by
   substituting a breakpoint at the specified address. The implementation must
   substituting a breakpoint at the specified address. The implementation must
   cope with the possibility of duplicate packets.
   cope with the possibility of duplicate packets.
 
 
   @todo This doesn't work with icache/immu yet
   @todo This doesn't work with icache/immu yet
 
 
   @param[in] buf  The command received                                      */
   @param[in] buf  The command received                                      */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
rsp_insert_matchpoint (struct rsp_buf *buf)
rsp_insert_matchpoint (struct rsp_buf *buf)
{
{
  enum mp_type       type;              /* What sort of matchpoint */
  enum mp_type       type;              /* What sort of matchpoint */
  unsigned long int  addr;              /* Address specified */
  unsigned long int  addr;              /* Address specified */
  int                len;               /* Matchpoint length (not used) */
  int                len;               /* Matchpoint length (not used) */
  unsigned long instbuf[1];
  unsigned long instbuf[1];
 
 
  /* Break out the instruction */
  /* Break out the instruction */
  if (3 != sscanf (buf->data, "Z%1d,%lx,%1d", (int *)&type, &addr, &len))
  if (3 != sscanf (buf->data, "Z%1d,%lx,%1d", (int *)&type, &addr, &len))
    {
    {
      fprintf (stderr, "Warning: RSP matchpoint insertion request not "
      fprintf (stderr, "Warning: RSP matchpoint insertion request not "
               "recognized: ignored\n");
               "recognized: ignored\n");
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
    }
    }
 
 
  /* Sanity check that the length is 4 */
  /* Sanity check that the length is 4 */
  if (4 != len)
  if (4 != len)
    {
    {
      fprintf (stderr, "Warning: RSP matchpoint insertion length %d not "
      fprintf (stderr, "Warning: RSP matchpoint insertion length %d not "
               "valid: 4 assumed\n", len);
               "valid: 4 assumed\n", len);
      len = 4;
      len = 4;
    }
    }
 
 
  /* Sort out the type of matchpoint */
  /* Sort out the type of matchpoint */
  switch (type)
  switch (type)
    {
    {
    case BP_MEMORY:
    case BP_MEMORY:
      /* Memory breakpoint - substitute a TRAP instruction */
      /* Memory breakpoint - substitute a TRAP instruction */
      dbg_wb_read_block32(addr, instbuf, 1);  // Get the old instruction.  *** TODO Check return value
      dbg_wb_read_block32(addr, instbuf, 1);  // Get the old instruction.  *** TODO Check return value
      mp_hash_add (type, addr, instbuf[0]);
      mp_hash_add (type, addr, instbuf[0]);
      instbuf[0] = OR1K_TRAP_INSTR;  // Set the TRAP instruction
      instbuf[0] = OR1K_TRAP_INSTR;  // Set the TRAP instruction
      dbg_wb_write_block32(addr, instbuf, 1);  // *** TODO Check return value
      dbg_wb_write_block32(addr, instbuf, 1);  // *** TODO Check return value
      put_str_packet ("OK");
      put_str_packet ("OK");
 
 
      return;
      return;
 
 
    case BP_HARDWARE:
    case BP_HARDWARE:
      put_str_packet ("");              /* Not supported */
      put_str_packet ("");              /* Not supported */
      return;
      return;
 
 
    case WP_WRITE:
    case WP_WRITE:
      put_str_packet ("");              /* Not supported */
      put_str_packet ("");              /* Not supported */
      return;
      return;
 
 
    case WP_READ:
    case WP_READ:
      put_str_packet ("");              /* Not supported */
      put_str_packet ("");              /* Not supported */
      return;
      return;
 
 
    case WP_ACCESS:
    case WP_ACCESS:
      put_str_packet ("");              /* Not supported */
      put_str_packet ("");              /* Not supported */
      return;
      return;
 
 
    default:
    default:
      fprintf (stderr, "Warning: RSP matchpoint type %d not "
      fprintf (stderr, "Warning: RSP matchpoint type %d not "
               "recognized: ignored\n", type);
               "recognized: ignored\n", type);
      put_str_packet ("E01");
      put_str_packet ("E01");
      return;
      return;
 
 
    }
    }
 
 
}       /* rsp_insert_matchpoint () */
}       /* rsp_insert_matchpoint () */
 
 
 
 
// Additions from this point on were added solely to handle hardware,
// Additions from this point on were added solely to handle hardware,
// and did not come from simulator interface code.
// and did not come from simulator interface code.
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//
//
//  Thread to poll for break on remote processor.
//  Thread to poll for break on remote processor.
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
 
 
void *target_handler(void *arg)
void *target_handler(void *arg)
{
{
  unsigned char target_status = 0;
  unsigned char target_status = 0;
  int retval = APP_ERR_NONE;
  int retval = APP_ERR_NONE;
  char string[] = "a";  // We send this through the pipe.  Content is unimportant.
  char string[] = "a";  // We send this through the pipe.  Content is unimportant.
  unsigned int local_state = 0;
  unsigned int local_state = 0;
 
 
  while(1)
  while(1)
    {
    {
      // Block on condition for GO or DETACH signal
      // Block on condition for GO or DETACH signal
      pthread_mutex_lock(&target_handler_mutex);
      pthread_mutex_lock(&target_handler_mutex);
      if(target_handler_state == 0)
      if(target_handler_state == 0)
        {
        {
          pthread_cond_wait(&target_handler_cond, &target_handler_mutex);
          pthread_cond_wait(&target_handler_cond, &target_handler_mutex);
        }
        }
 
 
      // if detach, exit thread
      // if detach, exit thread
      if(target_handler_state == 2)  // 2 = DETACH
      if(target_handler_state == 2)  // 2 = DETACH
        {
        {
          target_handler_state = 0;
          target_handler_state = 0;
          pthread_mutex_unlock(&target_handler_mutex);
          pthread_mutex_unlock(&target_handler_mutex);
          return arg;
          return arg;
        }
        }
 
 
      local_state = target_handler_state;
      local_state = target_handler_state;
      pthread_mutex_unlock(&target_handler_mutex);
      pthread_mutex_unlock(&target_handler_mutex);
 
 
 
 
 
 
      if(local_state == 1)  // Then start target polling loop, but keep checking for DETACH.  State 1 == GO
      if(local_state == 1)  // Then start target polling loop, but keep checking for DETACH.  State 1 == GO
        {
        {
          while(1)
          while(1)
            {
            {
              // non-blocking check for DETACH signal
              // non-blocking check for DETACH signal
              pthread_mutex_lock(&target_handler_mutex);
              pthread_mutex_lock(&target_handler_mutex);
              if(target_handler_state == 2)  // state 2 == DETACH
              if(target_handler_state == 2)  // state 2 == DETACH
                {
                {
                  pthread_mutex_unlock(&target_handler_mutex);
                  pthread_mutex_unlock(&target_handler_mutex);
                  return arg;
                  return arg;
                }
                }
              pthread_mutex_unlock(&target_handler_mutex);
              pthread_mutex_unlock(&target_handler_mutex);
 
 
              // Poll target hardware
              // Poll target hardware
              retval = dbg_cpu0_read_ctrl(0, &target_status);
              retval = dbg_cpu0_read_ctrl(0, &target_status);
              if(retval != APP_ERR_NONE)
              if(retval != APP_ERR_NONE)
                fprintf(stderr, "ERROR 0x%X while polling target CPU status\n", retval);
                fprintf(stderr, "ERROR 0x%X while polling target CPU status\n", retval);
              else {
              else {
                if(target_status & 0x01)  // Did we get the stall bit?  Bit 0 is STALL bit.
                if(target_status & 0x01)  // Did we get the stall bit?  Bit 0 is STALL bit.
                  {
                  {
                    // clear the RUNNING flag
                    // clear the RUNNING flag
                    pthread_mutex_lock(&rsp_mutex);
                    pthread_mutex_lock(&rsp_mutex);
                    rsp.target_running = 0;
                    rsp.target_running = 0;
                    pthread_mutex_unlock(&rsp_mutex);
                    pthread_mutex_unlock(&rsp_mutex);
 
 
                    // Log the exception so it can be sent back to GDB
                    // Log the exception so it can be sent back to GDB
                    unsigned long drrval;
                    unsigned long drrval;
                    dbg_cpu0_read(SPR_DRR, &drrval);  // Read the DRR, find out why we stopped
                    dbg_cpu0_read(SPR_DRR, &drrval);  // Read the DRR, find out why we stopped
                    rsp_exception(drrval);  // Send it to be translated and stored
                    rsp_exception(drrval);  // Send it to be translated and stored
 
 
                    // Send message to GDB handler thread via socket (so it can break out of its poll())
                    // Send message to GDB handler thread via socket (so it can break out of its poll())
                    int ret = write(pipe_fds[1], string, 1);
                    int ret = write(pipe_fds[1], string, 1);
                    if(!ret) {
                    if(!ret) {
                      fprintf(stderr, "Warning: target monitor write() to pipe returned 0\n");
                      fprintf(stderr, "Warning: target monitor write() to pipe returned 0\n");
                    }
                    }
                    else if(ret < 0) {
                    else if(ret < 0) {
                      perror("Error in target monitor write to pipe: ");
                      perror("Error in target monitor write to pipe: ");
                    }
                    }
 
 
                    // Set our own state back to STOP
                    // Set our own state back to STOP
                    pthread_mutex_lock(&target_handler_mutex);
                    pthread_mutex_lock(&target_handler_mutex);
                    target_handler_state = 0;
                    target_handler_state = 0;
                    pthread_mutex_unlock(&target_handler_mutex);
                    pthread_mutex_unlock(&target_handler_mutex);
 
 
                    break;  // Stop polling, block on the next GO/DETACH
                    break;  // Stop polling, block on the next GO/DETACH
                  }
                  }
              }
              }
 
 
              usleep(250000);  // wait 1/4 second before polling again.
              usleep(250000);  // wait 1/4 second before polling again.
            }
            }
        }
        }
 
 
      else
      else
        {
        {
          fprintf(stderr, "Unknown command 0x%X received by target handler thread\n", local_state);
          fprintf(stderr, "Unknown command 0x%X received by target handler thread\n", local_state);
          pthread_mutex_lock(&target_handler_mutex);  // Set our own state back to STOP
          pthread_mutex_lock(&target_handler_mutex);  // Set our own state back to STOP
          target_handler_state = 0;
          target_handler_state = 0;
          pthread_mutex_unlock(&target_handler_mutex);
          pthread_mutex_unlock(&target_handler_mutex);
        }
        }
    }
    }
 
 
  return arg;
  return arg;
}
}
 
 
 
 
 
 
 
 
void set_stall_state(int stall)
void set_stall_state(int stall)
{
{
  int retval = 0;
  int retval = 0;
  unsigned char data = (stall>0)? 1:0;
  unsigned char data = (stall>0)? 1:0;
  unsigned char stalled = 0;
  unsigned char stalled = 0;
 
 
  // Set the 'running' variable, if necessary.  Do this before actually starting the CPU.
  // Set the 'running' variable, if necessary.  Do this before actually starting the CPU.
  // The 'running' variable prevents us from responding to most GDB requests while the
  // The 'running' variable prevents us from responding to most GDB requests while the
  // CPU is running.
  // CPU is running.
  // We don't ever set the 'running' bit to 0 here.  Instead, we stall the CPU hardware, and let
  // We don't ever set the 'running' bit to 0 here.  Instead, we stall the CPU hardware, and let
  // the target handler thread detect the stall, then signal us to send a message up to
  // the target handler thread detect the stall, then signal us to send a message up to
  // GDB and clear the 'running' bit.
  // GDB and clear the 'running' bit.
  if(stall == 0)
  if(stall == 0)
    {
    {
      use_cached_npc = 0;
      use_cached_npc = 0;
      pthread_mutex_lock(&rsp_mutex);
      pthread_mutex_lock(&rsp_mutex);
      rsp.target_running = 1;
      rsp.target_running = 1;
      pthread_mutex_unlock(&rsp_mutex);
      pthread_mutex_unlock(&rsp_mutex);
    }
    }
 
 
  // Actually start or stop the CPU hardware
  // Actually start or stop the CPU hardware
  retval = dbg_cpu0_write_ctrl(0, data);  // 0x01 is the STALL command bit
  retval = dbg_cpu0_write_ctrl(0, data);  // 0x01 is the STALL command bit
  if(retval != APP_ERR_NONE)
  if(retval != APP_ERR_NONE)
    fprintf(stderr, "ERROR 0x%X sending async STALL to target.\n", retval);
    fprintf(stderr, "ERROR 0x%X sending async STALL to target.\n", retval);
 
 
  dbg_cpu0_read_ctrl(0, &stalled);
  dbg_cpu0_read_ctrl(0, &stalled);
  /*
  /*
    if (!(stalled & 0x1)) {
    if (!(stalled & 0x1)) {
    printf("or1k is not stalled!\n");
    printf("or1k is not stalled!\n");
    }
    }
 
 
    fprintf(stderr, "Set STALL to %i\n", data);
    fprintf(stderr, "Set STALL to %i\n", data);
  */
  */
 
 
  // Wake up the target handler thread to poll for a new STALL
  // Wake up the target handler thread to poll for a new STALL
  if(stall == 0)
  if(stall == 0)
    {
    {
      pthread_mutex_lock(&target_handler_mutex);
      pthread_mutex_lock(&target_handler_mutex);
      target_handler_state = 1;
      target_handler_state = 1;
      pthread_cond_signal(&target_handler_cond);
      pthread_cond_signal(&target_handler_cond);
      pthread_mutex_unlock(&target_handler_mutex);
      pthread_mutex_unlock(&target_handler_mutex);
    }
    }
 
 
  return;
  return;
}
}
 
 

powered by: WebSVN 2.1.0

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