Thu Mar 26 12:00:35 1998 Martin M. Hunt <hunt@cygnus.com>
[deliverable/binutils-gdb.git] / gdb / remote-mips.c
index 6e4e62ac86fd5942a4a7afe30f7da088e428b265..bdd50c56c29f1ad4b577f7812db0ae716a9a5897 100644 (file)
@@ -1,5 +1,5 @@
 /* Remote debugging interface for MIPS remote debugging protocol.
-   Copyright 1993 Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1995 Free Software Foundation, Inc.
    Contributed by Cygnus Support.  Written by Ian Lance Taylor
    <ian@cygnus.com>.
 
@@ -17,7 +17,7 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "defs.h"
 #include "inferior.h"
@@ -29,91 +29,143 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "serial.h"
 #include "target.h"
 #include "remote-utils.h"
+#include "gdb_string.h"
 
 #include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
 #include <varargs.h>
+#endif
+
+/* Microsoft C's stat.h doesn't define all the POSIX file modes.  */
+#ifndef S_IROTH
+#define S_IROTH S_IREAD
+#endif
+
+extern void mips_set_processor_type_command PARAMS ((char *, int));
+
 \f
+/* Breakpoint types.  Values 0, 1, and 2 must agree with the watch
+   types passed by breakpoint.c to target_insert_watchpoint.
+   Value 3 is our own invention, and is used for ordinary instruction
+   breakpoints.  Value 4 is used to mark an unused watchpoint in tables.  */
+enum break_type {
+  BREAK_WRITE, /* 0 */
+  BREAK_READ,  /* 1 */
+  BREAK_ACCESS,        /* 2 */
+  BREAK_FETCH, /* 3 */
+  BREAK_UNUSED /* 4 */
+};
+
 /* Prototypes for local functions.  */
 
-static int
-mips_readchar PARAMS ((int timeout));
+static int mips_readchar PARAMS ((int timeout));
 
-static int
-mips_receive_header PARAMS ((unsigned char *hdr, int *pgarbage, int ch,
-                            int timeout));
+static int mips_receive_header PARAMS ((unsigned char *hdr, int *pgarbage,
+                                       int ch, int timeout));
 
-static int
-mips_receive_trailer PARAMS ((unsigned char *trlr, int *pgarbage, int *pch,
-                             int timeout));
+static int mips_receive_trailer PARAMS ((unsigned char *trlr, int *pgarbage,
+                                        int *pch, int timeout));
 
 static int mips_cksum PARAMS ((const unsigned char *hdr,
                               const unsigned char *data,
                               int len));
 
-static void
-mips_send_packet PARAMS ((const char *s, int get_ack));
+static void mips_send_packet PARAMS ((const char *s, int get_ack));
+
+static void mips_send_command PARAMS ((const char *cmd, int prompt));
 
 static int mips_receive_packet PARAMS ((char *buff, int throw_error,
                                        int timeout));
 
-static int
-mips_request PARAMS ((char cmd, unsigned int addr, unsigned int data,
-                     int *perr, timeout));
+static CORE_ADDR mips_request PARAMS ((int cmd, CORE_ADDR addr,
+                                CORE_ADDR data, int *perr, int timeout,
+                                char *buff));
 
-static void
-mips_initialize PARAMS ((void));
+static void mips_initialize PARAMS ((void));
 
-static void
-mips_open PARAMS ((char *name, int from_tty));
+static void mips_open PARAMS ((char *name, int from_tty));
 
-static void
-mips_close PARAMS ((int quitting));
+static void pmon_open PARAMS ((char *name, int from_tty));
 
-static void
-mips_detach PARAMS ((char *args, int from_tty));
+static void ddb_open PARAMS ((char *name, int from_tty));
 
-static void
-mips_resume PARAMS ((int pid, int step, int siggnal));
+static void lsi_open PARAMS ((char *name, int from_tty));
 
-static int
-mips_wait PARAMS ((int pid, WAITTYPE *status));
+static void mips_close PARAMS ((int quitting));
 
-static int
-mips_map_regno PARAMS ((int regno));
+static void mips_detach PARAMS ((char *args, int from_tty));
 
-static void
-mips_fetch_registers PARAMS ((int regno));
+static void mips_resume PARAMS ((int pid, int step,
+                                enum target_signal siggnal));
 
-static void
-mips_prepare_to_store PARAMS ((void));
+static int mips_wait PARAMS ((int pid, struct target_waitstatus *status));
 
-static void
-mips_store_registers PARAMS ((int regno));
+static int mips_map_regno PARAMS ((int regno));
 
-static int
-mips_fetch_word PARAMS ((CORE_ADDR addr));
+static void mips_fetch_registers PARAMS ((int regno));
 
-static void
-mips_store_word PARAMS ((CORE_ADDR addr, int value));
+static void mips_prepare_to_store PARAMS ((void));
 
-static int
-mips_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len,
-                         int write, struct target_ops *ignore));
+static void mips_store_registers PARAMS ((int regno));
 
-static void
-mips_files_info PARAMS ((struct target_ops *ignore));
+static unsigned int mips_fetch_word PARAMS ((CORE_ADDR addr));
 
-static void
-mips_load PARAMS ((char *args, int from_tty));
+static int mips_store_word PARAMS ((CORE_ADDR addr, unsigned int value,
+                                   char *old_contents));
 
-static void
-mips_create_inferior PARAMS ((char *execfile, char *args, char **env));
+static int mips_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len,
+                                    int write, struct target_ops *ignore));
 
-static void
-mips_mourn_inferior PARAMS ((void));
+static void mips_files_info PARAMS ((struct target_ops *ignore));
+
+static void mips_create_inferior PARAMS ((char *execfile, char *args,
+                                         char **env));
+
+static void mips_mourn_inferior PARAMS ((void));
 
-/* A forward declaration.  */
+static int pmon_makeb64 PARAMS ((unsigned long v, char *p, int n, int *chksum));
+
+static int pmon_zeroset PARAMS ((int recsize, char **buff, int *amount,
+                                 unsigned int *chksum));
+
+static int pmon_checkset PARAMS ((int recsize, char **buff, int *value));
+
+static void pmon_make_fastrec PARAMS ((char **outbuf, unsigned char *inbuf,
+                                       int *inptr, int inamount, int *recsize,
+                                       unsigned int *csum, unsigned int *zerofill));
+
+static int pmon_check_ack PARAMS ((char *mesg));
+
+static void pmon_start_download PARAMS ((void));
+
+static void pmon_end_download PARAMS ((int final, int bintotal));
+
+static void pmon_download PARAMS ((char *buffer, int length));
+
+static void pmon_load_fast PARAMS ((char *file));
+
+static void mips_load PARAMS ((char *file, int from_tty));
+
+static int mips_make_srec PARAMS ((char *buffer, int type, CORE_ADDR memaddr,
+                                  unsigned char *myaddr, int len));
+
+static int set_breakpoint PARAMS ((CORE_ADDR addr, int len,
+                                  enum break_type type));
+
+static int clear_breakpoint PARAMS ((CORE_ADDR addr, int len,
+                                    enum break_type type));
+
+static int common_breakpoint PARAMS ((int set, CORE_ADDR addr, int len,
+                                     enum break_type type));
+
+/* Forward declarations.  */
 extern struct target_ops mips_ops;
+extern struct target_ops pmon_ops;
+extern struct target_ops ddb_ops;
 \f
 /* The MIPS remote debugging interface is built on top of a simple
    packet protocol.  Each packet is organized as follows:
@@ -140,7 +192,7 @@ extern struct target_ops mips_ops;
        The value is
                0x40 + seq
        An acknowlegment packet contains the sequence number of the
-       packet being acknowledged plus 1 module 64.  Data packets are
+       packet being acknowledged plus 1 modulo 64.  Data packets are
        transmitted in sequence.  There may only be one outstanding
        unacknowledged data packet at a time.  The sequence numbers
        are independent in each direction.  If an acknowledgement for
@@ -217,7 +269,7 @@ extern struct target_ops mips_ops;
   (((hdr)[HDR_INDX_TYPE_LEN] & TYPE_LEN_DA_BIT) == TYPE_LEN_DATA)
 #define HDR_GET_LEN(hdr) \
   ((((hdr)[HDR_INDX_TYPE_LEN] & 0x1f) << 6) + (((hdr)[HDR_INDX_LEN1] & 0x3f)))
-#define HDR_GET_SEQ(hdr) ((hdr)[HDR_INDX_SEQ] & 0x3f)
+#define HDR_GET_SEQ(hdr) ((unsigned int)(hdr)[HDR_INDX_SEQ] & 0x3f)
 
 /* The maximum data length.  */
 #define DATA_MAXLEN 1023
@@ -249,17 +301,59 @@ extern struct target_ops mips_ops;
 /* The sequence number modulos.  */
 #define SEQ_MODULOS (64)
 
+/* PMON commands to load from the serial port or UDP socket.  */
+#define LOAD_CMD       "load -b -s tty0\r"
+#define LOAD_CMD_UDP   "load -b -s udp\r"
+
+/* The target vectors for the four different remote MIPS targets.
+   These are initialized with code in _initialize_remote_mips instead
+   of static initializers, to make it easier to extend the target_ops
+   vector later.  */
+struct target_ops mips_ops, pmon_ops, ddb_ops, lsi_ops;
+
+enum mips_monitor_type {
+  /* IDT/SIM monitor being used: */
+  MON_IDT,
+  /* PMON monitor being used: */
+  MON_PMON, /* 3.0.83 [COGENT,EB,FP,NET] Algorithmics Ltd. Nov  9 1995 17:19:50 */
+  MON_DDB,  /* 2.7.473 [DDBVR4300,EL,FP,NET] Risq Modular Systems,  Thu Jun 6 09:28:40 PDT 1996 */
+  MON_LSI,  /* 4.3.12 [EB,FP], LSI LOGIC Corp. Tue Feb 25 13:22:14 1997 */
+  /* Last and unused value, for sizing vectors, etc. */
+  MON_LAST
+};
+static enum mips_monitor_type mips_monitor = MON_LAST;
+
+/* The monitor prompt text.  If the user sets the PMON prompt
+   to some new value, the GDB `set monitor-prompt' command must also
+   be used to inform GDB about the expected prompt.  Otherwise, GDB
+   will not be able to connect to PMON in mips_initialize().
+   If the `set monitor-prompt' command is not used, the expected
+   default prompt will be set according the target:
+       target          prompt
+       -----           -----
+       pmon            PMON> 
+       ddb             NEC010>
+       lsi             PMON>
+*/
+static char *mips_monitor_prompt;
+
 /* Set to 1 if the target is open.  */
 static int mips_is_open;
 
+/* Currently active target description (if mips_is_open == 1) */
+static struct target_ops *current_ops;
+
 /* Set to 1 while the connection is being initialized.  */
 static int mips_initializing;
 
+/* Set to 1 while the connection is being brought down.  */
+static int mips_exiting;
+
 /* The next sequence number to send.  */
-static int mips_send_seq;
+static unsigned int mips_send_seq;
 
 /* The next sequence number we expect to receive.  */
-static int mips_receive_seq;
+static unsigned int mips_receive_seq;
 
 /* The time to wait before retransmitting a packet, in seconds.  */
 static int mips_retransmit_wait = 3;
@@ -281,34 +375,143 @@ static int mips_need_reply = 0;
 /* Handle used to access serial I/O stream.  */
 static serial_t mips_desc;
 
+/* UDP handle used to download files to target.  */
+static serial_t udp_desc;
+static int udp_in_use;
+
+/* TFTP filename used to download files to DDB board, in the form
+   host:filename.  */
+static char *tftp_name;                /* host:filename */
+static char *tftp_localname;   /* filename portion of above */
+static int tftp_in_use;
+static FILE *tftp_file;
+
+/* Counts the number of times the user tried to interrupt the target (usually
+   via ^C.  */
+static int interrupt_count;
+
+/* If non-zero, means that the target is running. */
+static int mips_wait_flag = 0;
+
+/* If non-zero, monitor supports breakpoint commands. */
+static monitor_supports_breakpoints = 0;
+
+/* Data cache header.  */
+
+#if 0  /* not used (yet?) */
+static DCACHE *mips_dcache;
+#endif
+
+/* Non-zero means that we've just hit a read or write watchpoint */
+static int hit_watchpoint;
+
+/* Table of breakpoints/watchpoints (used only on LSI PMON target).
+   The table is indexed by a breakpoint number, which is an integer
+   from 0 to 255 returned by the LSI PMON when a breakpoint is set.
+*/
+#define MAX_LSI_BREAKPOINTS 256
+struct lsi_breakpoint_info
+{
+  enum break_type type;                /* type of breakpoint */
+  CORE_ADDR addr;              /* address of breakpoint */
+  int len;                     /* length of region being watched */
+  unsigned long value;         /* value to watch */
+} lsi_breakpoints [MAX_LSI_BREAKPOINTS];
+
+/* Error/warning codes returned by LSI PMON for breakpoint commands.
+   Warning values may be ORed together; error values may not.  */
+#define W_WARN 0x100   /* This bit is set if the error code is a warning */
+#define W_MSK   0x101  /* warning: Range feature is supported via mask */
+#define W_VAL   0x102  /* warning: Value check is not supported in hardware */
+#define W_QAL   0x104  /* warning: Requested qualifiers are not supported in hardware */
+
+#define E_ERR  0x200   /* This bit is set if the error code is an error */
+#define E_BPT   0x200  /* error: No such breakpoint number */
+#define E_RGE   0x201  /* error: Range is not supported */
+#define E_QAL   0x202  /* error: The requested qualifiers can not be used */
+#define E_OUT   0x203  /* error: Out of hardware resources */
+#define E_NON   0x204  /* error: Hardware breakpoint not supported */
+
+struct lsi_error
+{
+  int code;            /* error code */
+  char *string;                /* string associated with this code */
+};
+
+struct lsi_error lsi_warning_table[] =
+{
+  { W_MSK,     "Range feature is supported via mask" },
+  { W_VAL,     "Value check is not supported in hardware" },
+  { W_QAL,     "Requested qualifiers are not supported in hardware" },
+  { 0,         NULL }
+};
+
+struct lsi_error lsi_error_table[] =
+{  
+  { E_BPT,     "No such breakpoint number" },
+  { E_RGE,     "Range is not supported" },
+  { E_QAL,     "The requested qualifiers can not be used" },
+  { E_OUT,     "Out of hardware resources" },
+  { E_NON,     "Hardware breakpoint not supported" },
+  { 0,         NULL }
+};
+
+/* Set to 1 with the 'set monitor-warnings' command to enable printing
+   of warnings returned by PMON when hardware breakpoints are used.  */
+static int monitor_warnings;
+
+
+static void
+close_ports()
+{
+  mips_is_open = 0;
+  SERIAL_CLOSE (mips_desc);
+
+  if (udp_in_use)
+    {
+      SERIAL_CLOSE (udp_desc);
+      udp_in_use = 0;
+    }
+  tftp_in_use = 0;
+}
+    
 /* Handle low-level error that we can't recover from.  Note that just
    error()ing out from target_wait or some such low-level place will cause
    all hell to break loose--the rest of GDB will tend to get left in an
    inconsistent state.  */
 
-static void NORETURN
+static NORETURN void
+#ifdef ANSI_PROTOTYPES
+mips_error (char *string, ...)
+#else
 mips_error (va_alist)
      va_dcl
+#endif
 {
   va_list args;
-  char *string;
 
+#ifdef ANSI_PROTOTYPES
+  va_start (args, string);
+#else
+  char *string;
   va_start (args);
+  string = va_arg (args, char *);
+#endif
   target_terminal_ours ();
   wrap_here("");                       /* Force out any buffered output */
   gdb_flush (gdb_stdout);
   if (error_pre_print)
     fprintf_filtered (gdb_stderr, error_pre_print);
-  string = va_arg (args, char *);
   vfprintf_filtered (gdb_stderr, string, args);
   fprintf_filtered (gdb_stderr, "\n");
   va_end (args);
+  gdb_flush (gdb_stderr);
 
   /* Clean up in such a way that mips_close won't try to talk to the
      board (it almost surely won't work since we weren't able to talk to
      it).  */
-  mips_is_open = 0;
-  SERIAL_CLOSE (mips_desc);
+  close_ports ();
 
   printf_unfiltered ("Ending remote MIPS debugging.\n");
   target_mourn_inferior ();
@@ -316,14 +519,144 @@ mips_error (va_alist)
   return_to_top_level (RETURN_ERROR);
 }
 
+/* putc_readable - print a character, displaying non-printable chars in
+   ^x notation or in hex.  */
+
+static void
+putc_readable (ch)
+     int ch;
+{
+  if (ch == '\n')
+    putchar_unfiltered ('\n');
+  else if (ch == '\r')
+    printf_unfiltered ("\\r");
+  else if (ch < 0x20)  /* ASCII control character */
+    printf_unfiltered ("^%c", ch + '@');
+  else if (ch >= 0x7f) /* non-ASCII characters (rubout or greater) */
+    printf_unfiltered ("[%02x]", ch & 0xff);
+  else
+    putchar_unfiltered (ch);
+}
+
+
+/* puts_readable - print a string, displaying non-printable chars in
+   ^x notation or in hex.  */
+
+static void
+puts_readable (string)
+     char *string;
+{
+  int c;
+
+  while ((c = *string++) != '\0')
+    putc_readable (c);
+}
+
+
+/* Wait until STRING shows up in mips_desc.  Returns 1 if successful, else 0 if
+   timed out.  TIMEOUT specifies timeout value in seconds.
+*/
+
+int
+mips_expect_timeout (string, timeout)
+     char *string;
+     int timeout;
+{
+  char *p = string;
+
+  if (remote_debug)
+    {
+      printf_unfiltered ("Expected \"");
+      puts_readable (string);
+      printf_unfiltered ("\", got \"");
+    }
+
+  immediate_quit = 1;
+  while (1)
+    {
+      int c;
+
+/* Must use SERIAL_READCHAR here cuz mips_readchar would get confused if we
+   were waiting for the mips_monitor_prompt... */
+
+      c = SERIAL_READCHAR (mips_desc, timeout);
+
+      if (c == SERIAL_TIMEOUT)
+       {
+         if (remote_debug)
+           printf_unfiltered ("\": FAIL\n");
+         return 0;
+       }
+
+      if (remote_debug)
+       putc_readable (c);
+
+      if (c == *p++)
+       {       
+         if (*p == '\0')
+           {
+             immediate_quit = 0;
+             if (remote_debug)
+             printf_unfiltered ("\": OK\n");
+             return 1;
+           }
+       }
+      else
+       {
+         p = string;
+         if (c == *p)
+           p++;
+       }
+    }
+}
+
+/* Wait until STRING shows up in mips_desc.  Returns 1 if successful, else 0 if
+   timed out.  The timeout value is hard-coded to 2 seconds.  Use
+   mips_expect_timeout if a different timeout value is needed.
+*/
+
+int
+mips_expect (string)
+     char *string;
+{
+    return mips_expect_timeout (string, 2);
+}
+
+/* Read the required number of characters into the given buffer (which
+   is assumed to be large enough). The only failure is a timeout. */
+int
+mips_getstring (string, n)
+     char *string;
+     int n;
+{
+  char *p = string;
+  int c;
+
+  immediate_quit = 1;
+  while (n > 0)
+    {
+      c = SERIAL_READCHAR (mips_desc, 2);
+
+      if (c == SERIAL_TIMEOUT) {
+        fprintf_unfiltered (stderr, "Failed to read %d characters from target (TIMEOUT)\n", n);
+       return 0;
+      }
+
+      *p++ = c;
+      n--;
+    }
+
+  return 1;
+}
+
 /* Read a character from the remote, aborting on error.  Returns
    SERIAL_TIMEOUT on timeout (since that's what SERIAL_READCHAR
-   returns).  FIXME: If we see the string "<IDT>" from the board, then
-   we are debugging on the main console port, and we have somehow
-   dropped out of remote debugging mode.  In this case, we
-   automatically go back in to remote debugging mode.  This is a hack,
-   put in because I can't find any way for a program running on the
-   remote board to terminate without also ending remote debugging
+   returns).  FIXME: If we see the string mips_monitor_prompt from
+   the board, then we are debugging on the main console port, and we
+   have somehow dropped out of remote debugging mode.  In this case,
+   we automatically go back in to remote debugging mode.  This is a
+   hack, put in because I can't find any way for a program running on
+   the remote board to terminate without also ending remote debugging
    mode.  I assume users won't have any trouble with this; for one
    thing, the IDT documentation generally assumes that the remote
    debugging port is not the console port.  This is, however, very
@@ -336,44 +669,69 @@ mips_readchar (timeout)
 {
   int ch;
   static int state = 0;
-  static char nextstate[5] = { '<', 'I', 'D', 'T', '>' };
+  int mips_monitor_prompt_len = strlen (mips_monitor_prompt);
+
+#ifdef MAINTENANCE_CMDS
+  {
+    int i;
+
+    i = timeout;
+    if (i == -1 && watchdog > 0)
+     i = watchdog;
+  }
+#endif
 
+  if (state == mips_monitor_prompt_len)
+    timeout = 1;
   ch = SERIAL_READCHAR (mips_desc, timeout);
+#ifdef MAINTENANCE_CMDS
+  if (ch == SERIAL_TIMEOUT && timeout == -1) /* Watchdog went off */
+    {
+      target_mourn_inferior ();
+      error ("Watchdog has expired.  Target detached.\n");
+    }
+#endif
   if (ch == SERIAL_EOF)
     mips_error ("End of file from remote");
   if (ch == SERIAL_ERROR)
     mips_error ("Error reading from remote: %s", safe_strerror (errno));
-  if (sr_get_debug () > 1)
+  if (remote_debug > 1)
     {
+      /* Don't use _filtered; we can't deal with a QUIT out of
+        target_wait, and I think this might be called from there.  */
       if (ch != SERIAL_TIMEOUT)
-       printf_filtered ("Read '%c' %d 0x%x\n", ch, ch, ch);
+       printf_unfiltered ("Read '%c' %d 0x%x\n", ch, ch, ch);
       else
-       printf_filtered ("Timed out in read\n");
+       printf_unfiltered ("Timed out in read\n");
     }
 
-  /* If we have seen <IDT> and we either time out, or we see a @
-     (which was echoed from a packet we sent), reset the board as
-     described above.  The first character in a packet after the SYN
-     (which is not echoed) is always an @ unless the packet is more
-     than 64 characters long, which ours never are.  */
+  /* If we have seen mips_monitor_prompt and we either time out, or
+     we see a @ (which was echoed from a packet we sent), reset the
+     board as described above.  The first character in a packet after
+     the SYN (which is not echoed) is always an @ unless the packet is
+     more than 64 characters long, which ours never are.  */
   if ((ch == SERIAL_TIMEOUT || ch == '@')
-      && state == 5
-      && ! mips_initializing)
+      && state == mips_monitor_prompt_len
+      && ! mips_initializing
+      && ! mips_exiting)
     {
-      if (sr_get_debug () > 0)
-       printf_filtered ("Reinitializing MIPS debugging mode\n");
-      SERIAL_WRITE (mips_desc, "\rdb tty0\r", sizeof "\rdb tty0\r" - 1);
-      sleep (1);
+      if (remote_debug > 0)
+       /* Don't use _filtered; we can't deal with a QUIT out of
+          target_wait, and I think this might be called from there.  */
+       printf_unfiltered ("Reinitializing MIPS debugging mode\n");
 
       mips_need_reply = 0;
       mips_initialize ();
 
       state = 0;
 
-      mips_error ("Remote board reset");
+      /* At this point, about the only thing we can do is abort the command
+        in progress and get back to command level as quickly as possible. */
+
+      error ("Remote board reset, debug protocol re-initialized.");
     }
 
-  if (ch == nextstate[state])
+  if (ch == mips_monitor_prompt[state])
     ++state;
   else
     state = 0;
@@ -405,22 +763,24 @@ mips_receive_header (hdr, pgarbage, ch, timeout)
        {
          ch = mips_readchar (timeout);
          if (ch == SERIAL_TIMEOUT)
-           return -1;
+           return -1;
          if (ch != SYN)
            {
              /* Printing the character here lets the user of gdb see
                 what the program is outputting, if the debugging is
-                being done on the console port.  FIXME: Perhaps this
-                should be filtered?  */
-             if (! mips_initializing || sr_get_debug () > 0)
+                being done on the console port.  Don't use _filtered;
+                we can't deal with a QUIT out of target_wait.  */
+             if (! mips_initializing || remote_debug > 0)
                {
-                 putchar_unfiltered (ch);
+                 putc_readable (ch);
                  gdb_flush (gdb_stdout);
                }
 
              ++*pgarbage;
-             if (*pgarbage > mips_syn_garbage)
-               mips_error ("Remote debugging protocol failure");
+             if (mips_syn_garbage > 0
+                 && *pgarbage > mips_syn_garbage)
+               mips_error ("Debug protocol failure:  more than %d characters before a sync.", 
+                           mips_syn_garbage);
            }
        }
 
@@ -429,8 +789,7 @@ mips_receive_header (hdr, pgarbage, ch, timeout)
        {
          ch = mips_readchar (timeout);
          if (ch == SERIAL_TIMEOUT)
-           return -1;
-
+            return -1;
          /* Make sure this is a header byte.  */
          if (ch == SYN || ! HDR_CHECK (ch))
            break;
@@ -441,7 +800,7 @@ mips_receive_header (hdr, pgarbage, ch, timeout)
       /* If we got the complete header, we can return.  Otherwise we
         loop around and keep looking for SYN.  */
       if (i >= HDR_LENGTH)
-       return 0;
+        return 0;
     }
 }
 
@@ -509,7 +868,7 @@ mips_send_packet (s, get_ack)
      const char *s;
      int get_ack;
 {
-  unsigned int len;
+  /* unsigned */ int len;
   unsigned char *packet;
   register int cksum;
   int try;
@@ -536,9 +895,6 @@ mips_send_packet (s, get_ack)
      the sequence number we expect in the acknowledgement.  */
   mips_send_seq = (mips_send_seq + 1) % SEQ_MODULOS;
 
-  if (! get_ack)
-    return;
-
   /* We can only have one outstanding data packet, so we just wait for
      the acknowledgement here.  Keep retransmitting the packet until
      we get one, or until we've tried too many times.  */
@@ -547,16 +903,21 @@ mips_send_packet (s, get_ack)
       int garbage;
       int ch;
 
-      if (sr_get_debug () > 0)
+      if (remote_debug > 0)
        {
+         /* Don't use _filtered; we can't deal with a QUIT out of
+            target_wait, and I think this might be called from there.  */
          packet[HDR_LENGTH + len + TRLR_LENGTH] = '\0';
-         printf_filtered ("Writing \"%s\"\n", packet + 1);
+         printf_unfiltered ("Writing \"%s\"\n", packet + 1);
        }
 
       if (SERIAL_WRITE (mips_desc, packet,
                        HDR_LENGTH + len + TRLR_LENGTH) != 0)
        mips_error ("write to target failed: %s", safe_strerror (errno));
 
+      if (! get_ack)
+       return;
+
       garbage = 0;
       ch = 0;
       while (1)
@@ -564,7 +925,7 @@ mips_send_packet (s, get_ack)
          unsigned char hdr[HDR_LENGTH + 1];
          unsigned char trlr[TRLR_LENGTH + 1];
          int err;
-         int seq;
+         unsigned int seq;
 
          /* Get the packet header.  If we time out, resend the data
             packet.  */
@@ -578,8 +939,36 @@ mips_send_packet (s, get_ack)
             ignore it.  FIXME: If the acknowledgement is lost, this
             data packet may be the packet the remote sends after the
             acknowledgement.  */
-         if (HDR_IS_DATA (hdr))
+         if (HDR_IS_DATA (hdr)) {
+            int i;
+
+            /* Ignore any errors raised whilst attempting to ignore
+               packet. */
+
+            len = HDR_GET_LEN (hdr);
+
+            for (i = 0; i < len; i++)
+              {
+                int rch;
+
+                rch = mips_readchar (2);
+                if (rch == SYN)
+                  {
+                    ch = SYN;
+                    break;
+                  }
+                if (rch == SERIAL_TIMEOUT)
+                  break;
+                /* ignore the character */
+              }
+
+            if (i == len)
+              (void) mips_receive_trailer (trlr, &garbage, &ch, 2);
+
+            /* We don't bother checking the checksum, or providing an
+               ACK to the packet. */
            continue;
+          }
 
          /* If the length is not 0, this is a garbled packet.  */
          if (HDR_GET_LEN (hdr) != 0)
@@ -603,11 +992,13 @@ mips_send_packet (s, get_ack)
              != TRLR_GET_CKSUM (trlr))
            continue;
 
-         if (sr_get_debug () > 0)
+         if (remote_debug > 0)
            {
              hdr[HDR_LENGTH] = '\0';
              trlr[TRLR_LENGTH] = '\0';
-             printf_filtered ("Got ack %d \"%s%s\"\n",
+             /* Don't use _filtered; we can't deal with a QUIT out of
+                target_wait, and I think this might be called from there.  */
+             printf_unfiltered ("Got ack %d \"%s%s\"\n",
                               HDR_GET_SEQ (hdr), hdr + 1, trlr);
            }
 
@@ -672,22 +1063,23 @@ mips_receive_packet (buff, throw_error, timeout)
       /* An acknowledgement is probably a duplicate; ignore it.  */
       if (! HDR_IS_DATA (hdr))
        {
-         if (sr_get_debug () > 0)
-           printf_filtered ("Ignoring unexpected ACK\n");
-         continue;
-       }
-
-      /* If this is the wrong sequence number, ignore it.  */
-      if (HDR_GET_SEQ (hdr) != mips_receive_seq)
-       {
-         if (sr_get_debug () > 0)
-           printf_filtered ("Ignoring sequence number %d (want %d)\n",
-                            HDR_GET_SEQ (hdr), mips_receive_seq);
+          len = HDR_GET_LEN (hdr);
+          /* Check if the length is valid for an ACK, we may aswell
+             try and read the remainder of the packet: */
+          if (len == 0)
+            {
+              /* Ignore the error condition, since we are going to
+                 ignore the packet anyway. */
+              (void) mips_receive_trailer (trlr, &garbage, &ch, timeout);
+            }
+         /* Don't use _filtered; we can't deal with a QUIT out of
+            target_wait, and I think this might be called from there.  */
+         if (remote_debug > 0)
+           printf_unfiltered ("Ignoring unexpected ACK\n");
          continue;
        }
 
       len = HDR_GET_LEN (hdr);
-
       for (i = 0; i < len; i++)
        {
          int rch;
@@ -710,8 +1102,10 @@ mips_receive_packet (buff, throw_error, timeout)
 
       if (i < len)
        {
-         if (sr_get_debug () > 0)
-           printf_filtered ("Got new SYN after %d chars (wanted %d)\n",
+         /* Don't use _filtered; we can't deal with a QUIT out of
+            target_wait, and I think this might be called from there.  */
+         if (remote_debug > 0)
+           printf_unfiltered ("Got new SYN after %d chars (wanted %d)\n",
                             i, len);
          continue;
        }
@@ -726,16 +1120,31 @@ mips_receive_packet (buff, throw_error, timeout)
        }
       if (err == -2)
        {
-         if (sr_get_debug () > 0)
-           printf_filtered ("Got SYN when wanted trailer\n");
+         /* Don't use _filtered; we can't deal with a QUIT out of
+            target_wait, and I think this might be called from there.  */
+         if (remote_debug > 0)
+           printf_unfiltered ("Got SYN when wanted trailer\n");
+         continue;
+       }
+
+      /* If this is the wrong sequence number, ignore it.  */
+      if (HDR_GET_SEQ (hdr) != mips_receive_seq)
+       {
+         /* Don't use _filtered; we can't deal with a QUIT out of
+            target_wait, and I think this might be called from there.  */
+         if (remote_debug > 0)
+           printf_unfiltered ("Ignoring sequence number %d (want %d)\n",
+                            HDR_GET_SEQ (hdr), mips_receive_seq);
          continue;
        }
 
       if (mips_cksum (hdr, buff, len) == TRLR_GET_CKSUM (trlr))
-       break;
+        break;
 
-      if (sr_get_debug () > 0)
-       printf_filtered ("Bad checksum; data %d, trailer %d\n",
+      if (remote_debug > 0)
+       /* Don't use _filtered; we can't deal with a QUIT out of
+          target_wait, and I think this might be called from there.  */
+       printf_unfiltered ("Bad checksum; data %d, trailer %d\n",
                         mips_cksum (hdr, buff, len),
                         TRLR_GET_CKSUM (trlr));
 
@@ -752,10 +1161,12 @@ mips_receive_packet (buff, throw_error, timeout)
       ack[HDR_LENGTH + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum);
       ack[HDR_LENGTH + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum);
 
-      if (sr_get_debug () > 0)
+      if (remote_debug > 0)
        {
          ack[HDR_LENGTH + TRLR_LENGTH] = '\0';
-         printf_filtered ("Writing ack %d \"%s\"\n", mips_receive_seq,
+         /* Don't use _filtered; we can't deal with a QUIT out of
+            target_wait, and I think this might be called from there.  */
+         printf_unfiltered ("Writing ack %d \"%s\"\n", mips_receive_seq,
                           ack + 1);
        }
 
@@ -768,10 +1179,12 @@ mips_receive_packet (buff, throw_error, timeout)
        }
     }
 
-  if (sr_get_debug () > 0)
+  if (remote_debug > 0)
     {
       buff[len] = '\0';
-      printf_filtered ("Got packet \"%s\"\n", buff);
+      /* Don't use _filtered; we can't deal with a QUIT out of
+        target_wait, and I think this might be called from there.  */
+      printf_unfiltered ("Got packet \"%s\"\n", buff);
     }
 
   /* We got the packet.  Send an acknowledgement.  */
@@ -788,10 +1201,12 @@ mips_receive_packet (buff, throw_error, timeout)
   ack[HDR_LENGTH + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum);
   ack[HDR_LENGTH + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum);
 
-  if (sr_get_debug () > 0)
+  if (remote_debug > 0)
     {
       ack[HDR_LENGTH + TRLR_LENGTH] = '\0';
-      printf_filtered ("Writing ack %d \"%s\"\n", mips_receive_seq,
+      /* Don't use _filtered; we can't deal with a QUIT out of
+        target_wait, and I think this might be called from there.  */
+      printf_unfiltered ("Writing ack %d \"%s\"\n", mips_receive_seq,
                       ack + 1);
     }
 
@@ -831,26 +1246,30 @@ mips_receive_packet (buff, throw_error, timeout)
    occurs, it sets *PERR to 1 and sets errno according to what the
    target board reports.  */
 
-static int
-mips_request (cmd, addr, data, perr, timeout)
-     char cmd;
-     unsigned int addr;
-     unsigned int data;
+static CORE_ADDR 
+mips_request (cmd, addr, data, perr, timeout, buff)
+     int cmd;
+     CORE_ADDR addr;
+     CORE_ADDR data;
      int *perr;
      int timeout;
+     char *buff;
 {
-  char buff[DATA_MAXLEN + 1];
+  char myBuff[DATA_MAXLEN + 1];
   int len;
   int rpid;
   char rcmd;
   int rerrflg;
-  int rresponse;
-  
+  unsigned long rresponse;
+
+  if (buff == (char *) NULL)
+    buff = myBuff;
+
   if (cmd != '\0')
     {
       if (mips_need_reply)
        fatal ("mips_request: Trying to send command before reply");
-      sprintf (buff, "0x0 %c 0x%x 0x%x", cmd, addr, data);
+      sprintf (buff, "0x0 %c 0x%s 0x%s", cmd, paddr_nz (addr), paddr_nz (data));
       mips_send_packet (buff, 1);
       mips_need_reply = 1;
     }
@@ -866,7 +1285,7 @@ mips_request (cmd, addr, data, perr, timeout)
   len = mips_receive_packet (buff, 1, timeout);
   buff[len] = '\0';
 
-  if (sscanf (buff, "0x%x %c 0x%x 0x%x",
+  if (sscanf (buff, "0x%x %c 0x%x 0x%lx",
              &rpid, &rcmd, &rerrflg, &rresponse) != 4
       || (cmd != '\0' && rcmd != cmd))
     mips_error ("Bad response from remote board");
@@ -888,87 +1307,396 @@ mips_request (cmd, addr, data, perr, timeout)
   return rresponse;
 }
 
+static void
+mips_initialize_cleanups (arg)
+     PTR arg;
+{
+  mips_initializing = 0;
+}
+
+static void
+mips_exit_cleanups (arg)
+     PTR arg;
+{
+  mips_exiting = 0;
+}
+
+static void
+mips_send_command (cmd, prompt)
+     const char *cmd;
+     int prompt;
+{
+  SERIAL_WRITE (mips_desc, cmd, strlen(cmd));
+  mips_expect (cmd);
+  mips_expect ("\n");
+  if (prompt)
+    mips_expect (mips_monitor_prompt);
+}
+
+/* Enter remote (dbx) debug mode: */
+static void
+mips_enter_debug ()
+{
+  /* Reset the sequence numbers, ready for the new debug sequence: */
+  mips_send_seq = 0;
+  mips_receive_seq = 0;
+
+  if (mips_monitor != MON_IDT)
+    mips_send_command ("debug\r", 0);
+  else /* assume IDT monitor by default */
+    mips_send_command ("db tty0\r", 0);
+
+  sleep(1);
+  SERIAL_WRITE (mips_desc, "\r", sizeof "\r" - 1);
+
+  /* We don't need to absorb any spurious characters here, since the
+     mips_receive_header will eat up a reasonable number of characters
+     whilst looking for the SYN, however this avoids the "garbage"
+     being displayed to the user. */
+  if (mips_monitor != MON_IDT)
+    mips_expect ("\r");
+  
+  {
+    char buff[DATA_MAXLEN + 1];
+    if (mips_receive_packet (buff, 1, 3) < 0)
+      mips_error ("Failed to initialize (didn't receive packet).");
+  }
+}
+
+/* Exit remote (dbx) debug mode, returning to the monitor prompt: */
+static int
+mips_exit_debug ()
+{
+  int err;
+  struct cleanup *old_cleanups = make_cleanup (mips_exit_cleanups, NULL);
+
+  mips_exiting = 1;
+
+  if (mips_monitor != MON_IDT)
+    {
+      /* The DDB (NEC) and MiniRISC (LSI) versions of PMON exit immediately,
+         so we do not get a reply to this command: */
+      mips_request ('x', (unsigned int) 0, (unsigned int) 0, NULL,
+               mips_receive_wait, NULL);
+      mips_need_reply = 0;
+      if (!mips_expect (" break!"))
+        return -1;
+    }
+  else
+    mips_request ('x', (unsigned int) 0, (unsigned int) 0, &err,
+                  mips_receive_wait, NULL);
+
+  if (!mips_expect (mips_monitor_prompt))
+    return -1;
+
+  do_cleanups (old_cleanups);
+
+  return 0;
+}
+
 /* Initialize a new connection to the MIPS board, and make sure we are
    really connected.  */
 
 static void
 mips_initialize ()
 {
-  char cr;
-  char buff[DATA_MAXLEN + 1];
   int err;
+  struct cleanup *old_cleanups = make_cleanup (mips_initialize_cleanups, NULL);
+  int j;
+
+  /* What is this code doing here?  I don't see any way it can happen, and
+     it might mean mips_initializing didn't get cleared properly.
+     So I'll make it a warning.  */
 
   if (mips_initializing)
-    return;
+    {
+      warning ("internal error: mips_initialize called twice");
+      return;
+    }
 
+  mips_wait_flag = 0;
   mips_initializing = 1;
 
-  mips_send_seq = 0;
-  mips_receive_seq = 0;
-
-  /* The board seems to want to send us a packet.  I don't know what
-     it means.  The packet seems to be triggered by a carriage return
-     character, although perhaps any character would do.  */
-  cr = '\r';
-  SERIAL_WRITE (mips_desc, &cr, 1);
+  /* At this point, the packit protocol isn't responding.  We'll try getting
+     into the monitor, and restarting the protocol.  */
 
-  if (mips_receive_packet (buff, 0, 3) < 0)
+  /* Force the system into the monitor.  After this we *should* be at
+     the mips_monitor_prompt.  */
+  if (mips_monitor != MON_IDT)
+    j = 0; /* start by checking if we are already at the prompt */
+  else
+    j = 1; /* start by sending a break */
+  for (; j <= 4; j++)
     {
-      char cc;
+      switch (j)
+       {
+        case 0:                 /* First, try sending a CR */
+          SERIAL_FLUSH_INPUT (mips_desc);
+         SERIAL_WRITE (mips_desc, "\r", 1);
+          break;
+       case 1:                 /* First, try sending a break */
+         SERIAL_SEND_BREAK (mips_desc);
+         break;
+       case 2:                 /* Then, try a ^C */
+         SERIAL_WRITE (mips_desc, "\003", 1);
+         break;
+       case 3:                 /* Then, try escaping from download */
+         {
+            if (mips_monitor != MON_IDT)
+              {
+                char tbuff[7];
+
+                /* We shouldn't need to send multiple termination
+                   sequences, since the target performs line (or
+                   block) reads, and then processes those
+                   packets. In-case we were downloading a large packet
+                   we flush the output buffer before inserting a
+                   termination sequence. */
+                SERIAL_FLUSH_OUTPUT (mips_desc);
+                sprintf (tbuff, "\r/E/E\r");
+                SERIAL_WRITE (mips_desc, tbuff, 6);
+              }
+            else
+              {
+                char srec[10];
+                int i;
+
+                /* We are possibly in binary download mode, having
+                   aborted in the middle of an S-record.  ^C won't
+                   work because of binary mode.  The only reliable way
+                   out is to send enough termination packets (8 bytes)
+                   to fill up and then overflow the largest size
+                   S-record (255 bytes in this case).  This amounts to
+                   256/8 + 1 packets.
+                   */
+
+                mips_make_srec (srec, '7', 0, NULL, 0);
+
+                for (i = 1; i <= 33; i++)
+                  {
+                    SERIAL_WRITE (mips_desc, srec, 8);
+
+                    if (SERIAL_READCHAR (mips_desc, 0) >= 0)
+                      break;   /* Break immediatly if we get something from
+                                  the board. */
+                  }
+              }
+          }
+         break;
+       case 4:
+         mips_error ("Failed to initialize.");
+       }
 
-      /* We did not receive the packet we expected; try resetting the
-        board and trying again.  */
-      printf_filtered ("Failed to initialize; trying to reset board\n");
-      cc = '\003';
-      SERIAL_WRITE (mips_desc, &cc, 1);
-      sleep (2);
-      SERIAL_WRITE (mips_desc, "\rdb tty0\r", sizeof "\rdb tty0\r" - 1);
-      sleep (1);
-      cr = '\r';
-      SERIAL_WRITE (mips_desc, &cr, 1);
+      if (mips_expect (mips_monitor_prompt))
+       break;
     }
-  mips_receive_packet (buff, 1, 3);
 
-  mips_initializing = 0;
+  if (mips_monitor != MON_IDT)
+    {
+      /* Sometimes PMON ignores the first few characters in the first
+         command sent after a load.  Sending a blank command gets
+        around that.  */
+      mips_send_command ("\r", -1);
+
+      /* Ensure the correct target state: */
+      if (mips_monitor != MON_LSI)
+       mips_send_command ("set regsize 64\r", -1);
+      mips_send_command ("set hostport tty0\r", -1);
+      mips_send_command ("set brkcmd \"\"\r", -1);
+      /* Delete all the current breakpoints: */
+      mips_send_command ("db *\r", -1);
+      /* NOTE: PMON does not have breakpoint support through the
+         "debug" mode, only at the monitor command-line. */
+    }
+
+  mips_enter_debug ();
+
+  /* Clear all breakpoints: */
+  if ((mips_monitor == MON_IDT
+       && clear_breakpoint (BREAK_UNUSED, -1, 0) == 0)
+      || mips_monitor == MON_LSI)
+    monitor_supports_breakpoints = 1;
+  else
+    monitor_supports_breakpoints = 0;
+
+  do_cleanups (old_cleanups);
 
   /* If this doesn't call error, we have connected; we don't care if
      the request itself succeeds or fails.  */
+
   mips_request ('r', (unsigned int) 0, (unsigned int) 0, &err,
-               mips_receive_wait);
+               mips_receive_wait, NULL);
+  set_current_frame (create_new_frame (read_fp (), read_pc ()));
+  select_frame (get_current_frame (), 0);
 }
 
 /* Open a connection to the remote board.  */
-
 static void
-mips_open (name, from_tty)
+common_open (ops, name, from_tty, new_monitor, new_monitor_prompt)
+     struct target_ops *ops;
      char *name;
      int from_tty;
+     enum mips_monitor_type new_monitor;
+     char *new_monitor_prompt;
 {
+  char *ptype;
+  char *serial_port_name;
+  char *remote_name = 0;
+  char *local_name = 0;
+  char **argv;
+
   if (name == 0)
     error (
 "To open a MIPS remote debugging connection, you need to specify what serial\n\
-device is attached to the target board (e.g., /dev/ttya).");
+device is attached to the target board (e.g., /dev/ttya).\n"
+"If you want to use TFTP to download to the board, specify the name of a\n"
+"temporary file to be used by GDB for downloads as the second argument.\n"
+"This filename must be in the form host:filename, where host is the name\n"
+"of the host running the TFTP server, and the file must be readable by the\n"
+"world.  If the local name of the temporary file differs from the name as\n"
+"seen from the board via TFTP, specify that name as the third parameter.\n");
+
+  /* Parse the serial port name, the optional TFTP name, and the
+     optional local TFTP name.  */
+  if ((argv = buildargv (name)) == NULL)
+    nomem(0);
+  make_cleanup (freeargv, (char *) argv);
+
+  serial_port_name = strsave (argv[0]);
+  if (argv[1])                         /* remote TFTP name specified? */
+    {
+      remote_name = argv[1];
+      if (argv[2])                     /* local TFTP filename specified? */
+       local_name = argv[2];
+    }
 
   target_preopen (from_tty);
 
   if (mips_is_open)
-    unpush_target (&mips_ops);
+    unpush_target (current_ops);
 
-  mips_desc = SERIAL_OPEN (name);
+  /* Open and initialize the serial port.  */
+  mips_desc = SERIAL_OPEN (serial_port_name);
   if (mips_desc == (serial_t) NULL)
-    perror_with_name (name);
-
-  SERIAL_RAW (mips_desc);
+    perror_with_name (serial_port_name);
 
-  mips_is_open = 1;
+  if (baud_rate != -1)
+    {
+      if (SERIAL_SETBAUDRATE (mips_desc, baud_rate))
+        {
+          SERIAL_CLOSE (mips_desc);
+          perror_with_name (serial_port_name);
+        }
+    }
 
-  mips_initialize ();
+  SERIAL_RAW (mips_desc);
+
+  /* Open and initialize the optional download port.  If it is in the form
+     hostname#portnumber, it's a UDP socket.  If it is in the form
+     hostname:filename, assume it's the TFTP filename that must be
+     passed to the DDB board to tell it where to get the load file.  */
+  if (remote_name)
+    {
+      if (strchr (remote_name, '#'))
+       {
+         udp_desc = SERIAL_OPEN (remote_name);
+         if (!udp_desc)
+           perror_with_name ("Unable to open UDP port");
+         udp_in_use = 1;
+       }
+      else
+       {
+         /* Save the remote and local names of the TFTP temp file.  If
+            the user didn't specify a local name, assume it's the same
+            as the part of the remote name after the "host:".  */
+         if (tftp_name)
+           free (tftp_name);
+         if (tftp_localname)
+           free (tftp_localname);
+         if (local_name == NULL)
+             if ((local_name = strchr (remote_name, ':')) != NULL)
+               local_name++;           /* skip over the colon */
+         if (local_name == NULL)
+           local_name = remote_name;   /* local name same as remote name */
+         tftp_name = strsave (remote_name);
+         tftp_localname = strsave (local_name);
+         tftp_in_use = 1;
+       }
+    }
+
+  current_ops = ops;
+  mips_is_open = 1;
+
+  /* Reset the expected monitor prompt if it's never been set before.  */
+  if (mips_monitor_prompt == NULL)
+    mips_monitor_prompt = strsave (new_monitor_prompt);
+  mips_monitor = new_monitor;
+
+  mips_initialize ();
 
   if (from_tty)
-    printf_unfiltered ("Remote MIPS debugging using %s\n", name);
-  push_target (&mips_ops);     /* Switch to using remote target now */
+    printf_unfiltered ("Remote MIPS debugging using %s\n", serial_port_name);
+
+  /* Switch to using remote target now.  */
+  push_target (ops);
 
   /* FIXME: Should we call start_remote here?  */
+
+  /* Try to figure out the processor model if possible.  */
+  ptype = mips_read_processor_type ();
+  if (ptype)
+    mips_set_processor_type_command (strsave (ptype), 0);
+
+/* This is really the job of start_remote however, that makes an assumption
+   that the target is about to print out a status message of some sort.  That
+   doesn't happen here (in fact, it may not be possible to get the monitor to
+   send the appropriate packet).  */
+
+  flush_cached_frames ();
+  registers_changed ();
+  stop_pc = read_pc ();
+  set_current_frame (create_new_frame (read_fp (), stop_pc));
+  select_frame (get_current_frame (), 0);
+  print_stack_frame (selected_frame, -1, 1);
+  free (serial_port_name);
+}
+
+static void
+mips_open (name, from_tty)
+     char *name;
+     int from_tty;
+{
+  common_open (&mips_ops, name, from_tty, MON_IDT, TARGET_MONITOR_PROMPT);
+}
+
+static void
+pmon_open (name, from_tty)
+     char *name;
+     int from_tty;
+{
+  common_open (&pmon_ops, name, from_tty, MON_PMON, "PMON> ");
+}
+
+static void
+ddb_open (name, from_tty)
+     char *name;
+     int from_tty;
+{
+  common_open (&ddb_ops, name, from_tty, MON_DDB, "NEC010>");
+}
+
+static void
+lsi_open (name, from_tty)
+     char *name;
+     int from_tty;
+{
+  int i;
+
+  /* Clear the LSI breakpoint table.  */
+  for (i = 0; i < MAX_LSI_BREAKPOINTS; i++)
+    lsi_breakpoints[i].type = BREAK_UNUSED;
+  
+  common_open (&lsi_ops, name, from_tty, MON_LSI, "PMON> ");
 }
 
 /* Close a connection to the remote board.  */
@@ -979,15 +1707,10 @@ mips_close (quitting)
 {
   if (mips_is_open)
     {
-      int err;
-
-      mips_is_open = 0;
-
       /* Get the board out of remote debugging mode.  */
-      mips_request ('x', (unsigned int) 0, (unsigned int) 0, &err,
-                   mips_receive_wait);
+      (void) mips_exit_debug ();
 
-      SERIAL_CLOSE (mips_desc);
+      close_ports ();
     }
 }
 
@@ -1002,26 +1725,51 @@ mips_detach (args, from_tty)
     error ("Argument given to \"detach\" when remotely debugging.");
 
   pop_target ();
+
+  mips_close (1);
+
   if (from_tty)
     printf_unfiltered ("Ending remote MIPS debugging.\n");
 }
 
 /* Tell the target board to resume.  This does not wait for a reply
-   from the board.  */
+   from the board, except in the case of single-stepping on LSI boards,
+   where PMON does return a reply.  */
 
 static void
 mips_resume (pid, step, siggnal)
-     int pid, step, siggnal;
+     int pid, step;
+     enum target_signal siggnal;
 {
-  if (siggnal)
-    mips_error ("Can't send signals to a remote system.  Try `handle %d ignore'.",
-          siggnal);
+  int err;
 
+  /* LSI PMON requires returns a reply packet "0x1 s 0x0 0x57f" after
+     a single step, so we wait for that.  */
   mips_request (step ? 's' : 'c',
                (unsigned int) 1,
-               (unsigned int) 0,
-               (int *) NULL,
-               mips_receive_wait);
+               (unsigned int) siggnal,
+               mips_monitor == MON_LSI && step ? &err : (int *) NULL,
+               mips_receive_wait, NULL);
+}
+
+/* Return the signal corresponding to SIG, where SIG is the number which
+   the MIPS protocol uses for the signal.  */
+enum target_signal
+mips_signal_from_protocol (sig)
+     int sig;
+{
+  /* We allow a few more signals than the IDT board actually returns, on
+     the theory that there is at least *some* hope that perhaps the numbering
+     for these signals is widely agreed upon.  */
+  if (sig <= 0
+      || sig > 31)
+    return TARGET_SIGNAL_UNKNOWN;
+
+  /* Don't want to use target_signal_from_host because we are converting
+     from MIPS signal numbers, not host ones.  Our internal numbers
+     match the MIPS numbers for the signals the board can return, which
+     are: SIGINT, SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP.  */
+  return (enum target_signal) sig;
 }
 
 /* Wait until the remote stops, and return a wait status.  */
@@ -1029,35 +1777,157 @@ mips_resume (pid, step, siggnal)
 static int
 mips_wait (pid, status)
      int pid;
-     WAITTYPE *status;
+     struct target_waitstatus *status;
 {
   int rstatus;
   int err;
+  char buff[DATA_MAXLEN];
+  int rpc, rfp, rsp;
+  char flags[20];
+  int nfields;
+  int i;
+
+  interrupt_count = 0;
+  hit_watchpoint = 0;
 
   /* If we have not sent a single step or continue command, then the
      board is waiting for us to do something.  Return a status
      indicating that it is stopped.  */
   if (! mips_need_reply)
     {
-      WSETSTOP (*status, SIGTRAP);
+      status->kind = TARGET_WAITKIND_STOPPED;
+      status->value.sig = TARGET_SIGNAL_TRAP;
       return 0;
     }
 
   /* No timeout; we sit here as long as the program continues to execute.  */
-  rstatus = mips_request ('\0', (unsigned int) 0, (unsigned int) 0, &err, -1);
+  mips_wait_flag = 1;
+  rstatus = mips_request ('\000', (unsigned int) 0, (unsigned int) 0, &err, -1,
+                         buff);
+  mips_wait_flag = 0;
   if (err)
     mips_error ("Remote failure: %s", safe_strerror (errno));
 
-  /* FIXME: The target board uses numeric signal values which are
-     those used on MIPS systems.  If the host uses different signal
-     values, we need to translate here.  I believe all Unix systems
-     use the same values for the signals the board can return, which
-     are: SIGINT, SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP.  */
+  /* On returning from a continue, the PMON monitor seems to start
+     echoing back the messages we send prior to sending back the
+     ACK. The code can cope with this, but to try and avoid the
+     unnecessary serial traffic, and "spurious" characters displayed
+     to the user, we cheat and reset the debug protocol. The problems
+     seems to be caused by a check on the number of arguments, and the
+     command length, within the monitor causing it to echo the command
+     as a bad packet. */
+  if (mips_monitor == MON_PMON)
+    {
+      mips_exit_debug ();
+      mips_enter_debug ();
+    }
+
+  /* See if we got back extended status.  If so, pick out the pc, fp, sp, etc... */
+
+  nfields = sscanf (buff, "0x%*x %*c 0x%*x 0x%*x 0x%x 0x%x 0x%x 0x%*x %s",
+                   &rpc, &rfp, &rsp, flags);
+  if (nfields >= 3)
+    {
+      char buf[MAX_REGISTER_RAW_SIZE];
+
+      store_unsigned_integer (buf, REGISTER_RAW_SIZE (PC_REGNUM), rpc);
+      supply_register (PC_REGNUM, buf);
+
+      store_unsigned_integer (buf, REGISTER_RAW_SIZE (PC_REGNUM), rfp);
+      supply_register (30, buf); /* This register they are avoiding and so it is unnamed */
 
-  /* FIXME: The target board uses a standard Unix wait status int.  If
-     the host system does not, we must translate here.  */
+      store_unsigned_integer (buf, REGISTER_RAW_SIZE (SP_REGNUM), rsp);
+      supply_register (SP_REGNUM, buf);
 
-  *status = rstatus;
+      store_unsigned_integer (buf, REGISTER_RAW_SIZE (FP_REGNUM), 0);
+      supply_register (FP_REGNUM, buf);
+
+      if (nfields == 9)
+       {
+         int i;
+
+         for (i = 0; i <= 2; i++)
+           if (flags[i] == 'r' || flags[i] == 'w')
+             hit_watchpoint = 1;
+           else if (flags[i] == '\000')
+             break;
+       }
+    }
+
+  if (strcmp (target_shortname, "lsi") == 0)
+    {
+#if 0
+      /* If this is an LSI PMON target, see if we just hit a hardrdware watchpoint.
+        Right now, PMON doesn't give us enough information to determine which
+        breakpoint we hit.  So we have to look up the PC in our own table
+        of breakpoints, and if found, assume it's just a normal instruction
+        fetch breakpoint, not a data watchpoint.  FIXME when PMON
+        provides some way to tell us what type of breakpoint it is.  */
+      int i;
+      CORE_ADDR pc = read_pc();
+
+      hit_watchpoint = 1;
+      for (i = 0; i < MAX_LSI_BREAKPOINTS; i++)
+       {
+         if (lsi_breakpoints[i].addr == pc
+             && lsi_breakpoints[i].type == BREAK_FETCH)
+           {
+             hit_watchpoint = 0;
+             break;
+           }
+       }
+#else
+      /* If a data breakpoint was hit, PMON returns the following packet:
+            0x1 c 0x0 0x57f 0x1
+        The return packet from an ordinary breakpoint doesn't have the
+        extra 0x01 field tacked onto the end.  */
+      if (nfields == 1 && rpc == 1)
+       hit_watchpoint = 1;
+#endif
+    }
+
+  /* NOTE: The following (sig) numbers are defined by PMON:
+       SPP_SIGTRAP     5       breakpoint
+        SPP_SIGINT      2
+        SPP_SIGSEGV     11
+        SPP_SIGBUS      10
+        SPP_SIGILL      4
+        SPP_SIGFPE      8
+        SPP_SIGTERM     15 */
+
+  /* Translate a MIPS waitstatus.  We use constants here rather than WTERMSIG
+     and so on, because the constants we want here are determined by the
+     MIPS protocol and have nothing to do with what host we are running on.  */
+  if ((rstatus & 0xff) == 0)
+    {
+      status->kind = TARGET_WAITKIND_EXITED;
+      status->value.integer = (((rstatus) >> 8) & 0xff);
+    }
+  else if ((rstatus & 0xff) == 0x7f)
+    {
+      status->kind = TARGET_WAITKIND_STOPPED;
+      status->value.sig = mips_signal_from_protocol (((rstatus) >> 8) & 0xff);
+
+      /* If the stop PC is in the _exit function, assume
+         we hit the 'break 0x3ff' instruction in _exit, so this
+        is not a normal breakpoint.  */
+      if (strcmp (target_shortname, "lsi") == 0)
+       {
+         char *func_name;
+         CORE_ADDR func_start;
+         CORE_ADDR pc = read_pc();
+
+         find_pc_partial_function (pc, &func_name, &func_start, NULL);
+         if (func_name != NULL && strcmp (func_name, "_exit") == 0
+             && func_start == pc)
+           status->kind = TARGET_WAITKIND_EXITED;
+       }
+    }
+  else
+    {
+      status->kind = TARGET_WAITKIND_SIGNALLED;
+      status->value.sig = mips_signal_from_protocol (rstatus & 0x7f);
+    }
 
   return 0;
 }
@@ -1112,10 +1982,33 @@ mips_fetch_registers (regno)
       return;
     }
 
-  val = mips_request ('r', (unsigned int) mips_map_regno (regno),
-                     (unsigned int) 0, &err, mips_receive_wait);
-  if (err)
-    mips_error ("Can't read register %d: %s", regno, safe_strerror (errno));
+  if (regno == FP_REGNUM || regno == ZERO_REGNUM)
+    /* FP_REGNUM on the mips is a hack which is just supposed to read
+       zero (see also mips-nat.c).  */
+    val = 0;
+  else
+    {
+      /* If PMON doesn't support this register, don't waste serial
+         bandwidth trying to read it.  */
+      int pmon_reg = mips_map_regno (regno);
+      if (regno != 0 && pmon_reg == 0)
+       val = 0;
+      else
+       {
+         /* Unfortunately the PMON version in the Vr4300 board has been
+            compiled without the 64bit register access commands. This
+            means we cannot get hold of the full register width. */
+         if (mips_monitor == MON_DDB)
+           val = (unsigned)mips_request ('t', (unsigned int) pmon_reg,
+                               (unsigned int) 0, &err, mips_receive_wait, NULL);
+         else
+           val = mips_request ('r', (unsigned int) pmon_reg,
+                               (unsigned int) 0, &err, mips_receive_wait, NULL);
+         if (err)
+           mips_error ("Can't read register %d: %s", regno,
+                       safe_strerror (errno));
+       }
+    }
 
   {
     char buf[MAX_REGISTER_RAW_SIZE];
@@ -1151,53 +2044,66 @@ mips_store_registers (regno)
     }
 
   mips_request ('R', (unsigned int) mips_map_regno (regno),
-               (unsigned int) read_register (regno),
-               &err, mips_receive_wait);
+               read_register (regno),
+               &err, mips_receive_wait, NULL);
   if (err)
     mips_error ("Can't write register %d: %s", regno, safe_strerror (errno));
 }
 
 /* Fetch a word from the target board.  */
 
-static int 
+static unsigned int 
 mips_fetch_word (addr)
      CORE_ADDR addr;
 {
-  int val;
+  unsigned int val;
   int err;
 
-  val = mips_request ('d', (unsigned int) addr, (unsigned int) 0, &err,
-                     mips_receive_wait);
+  /* FIXME! addr was cast to uint! */
+  val = mips_request ('d', addr, (unsigned int) 0, &err,
+                     mips_receive_wait, NULL);
   if (err)
     {
       /* Data space failed; try instruction space.  */
-      val = mips_request ('i', (unsigned int) addr, (unsigned int) 0, &err,
-                         mips_receive_wait);
+      /* FIXME! addr was cast to uint! */
+      val = mips_request ('i', addr, (unsigned int) 0, &err,
+                         mips_receive_wait, NULL);
       if (err)
-       mips_error ("Can't read address 0x%x: %s", addr, safe_strerror (errno));
+        mips_error ("Can't read address 0x%s: %s",
+             paddr_nz (addr), safe_strerror (errno));
     }
   return val;
 }
 
-/* Store a word to the target board.  */
+/* Store a word to the target board.  Returns errno code or zero for
+   success.  If OLD_CONTENTS is non-NULL, put the old contents of that
+   memory location there.  */
 
-static void
-mips_store_word (addr, val)
+/* FIXME! make sure only 32-bit quantities get stored! */
+static int
+mips_store_word (addr, val, old_contents)
      CORE_ADDR addr;
-     int val;
+     unsigned int val;
+     char *old_contents;
 {
   int err;
+  unsigned int oldcontents;
 
-  mips_request ('D', (unsigned int) addr, (unsigned int) val, &err,
-               mips_receive_wait);
+  oldcontents = mips_request ('D', addr, (unsigned int) val,
+                             &err,
+                             mips_receive_wait, NULL);
   if (err)
     {
       /* Data space failed; try instruction space.  */
-      mips_request ('I', (unsigned int) addr, (unsigned int) val, &err,
-                   mips_receive_wait);
+      oldcontents = mips_request ('I', addr,
+                                 (unsigned int) val, &err,
+                                 mips_receive_wait, NULL);
       if (err)
-       mips_error ("Can't write address 0x%x: %s", addr, safe_strerror (errno));
+       return errno;
     }
+  if (old_contents != NULL)
+    store_unsigned_integer (old_contents, 4, oldcontents);
+  return 0;
 }
 
 /* Read or write LEN bytes from inferior memory at MEMADDR,
@@ -1223,6 +2129,8 @@ mips_xfer_memory (memaddr, myaddr, len, write, ignore)
   /* Allocate buffer of that many longwords.  */
   register char *buffer = alloca (count * 4);
 
+  int status;
+
   if (write)
     {
       /* Fill start and end extra bytes of buffer with existing data.  */
@@ -1248,9 +2156,24 @@ mips_xfer_memory (memaddr, myaddr, len, write, ignore)
 
       for (i = 0; i < count; i++, addr += 4)
        {
-         mips_store_word (addr, extract_unsigned_integer (&buffer[i*4], 4));
+         status = mips_store_word (addr,
+                                   extract_unsigned_integer (&buffer[i*4], 4),
+                                   NULL);
+         /* Report each kilobyte (we download 32-bit words at a time) */
+         if (i % 256 == 255) 
+           {
+             printf_unfiltered ("*");
+             fflush (stdout);
+           }
+         if (status)
+           {
+             errno = status;
+             return 0;
+           }
          /* FIXME: Do we want a QUIT here?  */
        }
+      if (count >= 256)
+       printf_unfiltered ("\n");
     }
   else
     {
@@ -1284,6 +2207,40 @@ mips_files_info (ignore)
 static void
 mips_kill ()
 {
+  if (!mips_wait_flag)
+    return;
+
+  interrupt_count++;
+
+  if (interrupt_count >= 2)
+    {
+      interrupt_count = 0;
+
+      target_terminal_ours ();
+
+      if (query ("Interrupted while waiting for the program.\n\
+Give up (and stop debugging it)? "))
+       {
+         /* Clean up in such a way that mips_close won't try to talk to the
+            board (it almost surely won't work since we weren't able to talk to
+            it).  */
+         mips_wait_flag = 0;
+         close_ports();
+
+         printf_unfiltered ("Ending remote MIPS debugging.\n");
+         target_mourn_inferior ();
+
+         return_to_top_level (RETURN_QUIT);
+       }
+
+      target_terminal_inferior ();
+    }
+
+  if (remote_debug > 0)
+    printf_unfiltered ("Sending break\n");
+
+  SERIAL_SEND_BREAK (mips_desc);
+
 #if 0
   if (mips_is_open)
     {
@@ -1309,10 +2266,15 @@ mips_create_inferior (execfile, args, env)
   CORE_ADDR entry_pt;
 
   if (args && *args)
-    mips_error ("Can't pass arguments to remote MIPS board.");
+    {
+      warning ("\
+Can't pass arguments to remote MIPS board; arguments ignored.");
+      /* And don't try to use them on the next "run" command.  */
+      execute_command ("set args", 0);
+    }
 
   if (execfile == 0 || exec_bfd == 0)
-    mips_error ("No exec file specified");
+    error ("No executable file specified");
 
   entry_pt = (CORE_ADDR) bfd_get_start_address (exec_bfd);
 
@@ -1320,7 +2282,7 @@ mips_create_inferior (execfile, args, env)
 
   /* FIXME: Should we set inferior_pid here?  */
 
-  proceed (entry_pt, -1, 0);
+  proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0);
 }
 
 /* Clean up after a process.  Actually nothing to do.  */
@@ -1328,59 +2290,1284 @@ mips_create_inferior (execfile, args, env)
 static void
 mips_mourn_inferior ()
 {
-  unpush_target (&mips_ops);
+  if (current_ops != NULL)
+    unpush_target (current_ops);
   generic_mourn_inferior ();
 }
 \f
-/* The target vector.  */
-
-struct target_ops mips_ops =
-{
-  "mips",                      /* to_shortname */
-  "Remote MIPS debugging over serial line",    /* to_longname */
-  "Debug a board using the MIPS remote debugging protocol over a serial line.\n\
-Specify the serial device it is connected to (e.g., /dev/ttya).",  /* to_doc */
-  mips_open,                   /* to_open */
-  mips_close,                  /* to_close */
-  NULL,                                /* to_attach */
-  mips_detach,                 /* to_detach */
-  mips_resume,                 /* to_resume */
-  mips_wait,                   /* to_wait */
-  mips_fetch_registers,                /* to_fetch_registers */
-  mips_store_registers,                /* to_store_registers */
-  mips_prepare_to_store,       /* to_prepare_to_store */
-  mips_xfer_memory,            /* to_xfer_memory */
-  mips_files_info,             /* to_files_info */
-  NULL,                                /* to_insert_breakpoint */
-  NULL,                                /* to_remove_breakpoint */
-  NULL,                                /* to_terminal_init */
-  NULL,                                /* to_terminal_inferior */
-  NULL,                                /* to_terminal_ours_for_output */
-  NULL,                                /* to_terminal_ours */
-  NULL,                                /* to_terminal_info */
-  mips_kill,                   /* to_kill */
-  generic_load,                        /* to_load */
-  NULL,                                /* to_lookup_symbol */
-  mips_create_inferior,                /* to_create_inferior */
-  mips_mourn_inferior,         /* to_mourn_inferior */
-  NULL,                                /* to_can_run */
-  NULL,                                /* to_notice_signals */
-  process_stratum,             /* to_stratum */
-  NULL,                                /* to_next */
-  1,                           /* to_has_all_memory */
-  1,                           /* to_has_memory */
-  1,                           /* to_has_stack */
-  1,                           /* to_has_registers */
-  1,                           /* to_has_execution */
-  NULL,                                /* sections */
-  NULL,                                /* sections_end */
-  OPS_MAGIC                    /* to_magic */
-};
+/* We can write a breakpoint and read the shadow contents in one
+   operation.  */
+
+/* Insert a breakpoint.  On targets that don't have built-in breakpoint
+   support, we read the contents of the target location and stash it,
+   then overwrite it with a breakpoint instruction.  ADDR is the target
+   location in the target machine.  CONTENTS_CACHE is a pointer to 
+   memory allocated for saving the target contents.  It is guaranteed
+   by the caller to be long enough to save sizeof BREAKPOINT bytes (this
+   is accomplished via BREAKPOINT_MAX).  */
+
+static int
+mips_insert_breakpoint (addr, contents_cache)
+     CORE_ADDR addr;
+     char *contents_cache;
+{
+  if (monitor_supports_breakpoints)
+    return set_breakpoint (addr, MIPS_INSTLEN, BREAK_FETCH);
+  else
+    return memory_insert_breakpoint (addr, contents_cache);
+}
+
+static int
+mips_remove_breakpoint (addr, contents_cache)
+     CORE_ADDR addr;
+     char *contents_cache;
+{
+  if (monitor_supports_breakpoints)
+    return clear_breakpoint (addr, MIPS_INSTLEN, BREAK_FETCH);
+  else
+    return memory_remove_breakpoint (addr, contents_cache);
+}
+
+#if 0 /* currently not used */
+/* PMON does not currently provide support for the debug mode 'b'
+   commands to manipulate breakpoints. However, if we wanted to use
+   the monitor breakpoints (rather than the GDB BREAK_INSN version)
+   then this code performs the work needed to leave debug mode,
+   set/clear the breakpoint, and then return to debug mode. */
+
+#define PMON_MAX_BP (33) /* 32 SW, 1 HW */
+static CORE_ADDR mips_pmon_bp_info[PMON_MAX_BP];
+/* NOTE: The code relies on this vector being zero-initialised by the system */
+
+static int
+pmon_insert_breakpoint (addr, contents_cache)
+     CORE_ADDR addr;
+     char *contents_cache;
+{
+  int status;
+
+  if (monitor_supports_breakpoints)
+    {
+      char tbuff[12]; /* space for breakpoint command */
+      int bpnum;
+      CORE_ADDR bpaddr;
+
+      /* PMON does not support debug level breakpoint set/remove: */
+      if (mips_exit_debug ())
+        mips_error ("Failed to exit debug mode");
+
+      sprintf (tbuff, "b %08x\r", addr);
+      mips_send_command (tbuff, 0);
+
+      mips_expect ("Bpt ");
+
+      if (!mips_getstring (tbuff, 2))
+        return 1;
+      tbuff[2] = '\0'; /* terminate the string */
+      if (sscanf (tbuff, "%d", &bpnum) != 1)
+        {
+          fprintf_unfiltered (stderr, "Invalid decimal breakpoint number from target: %s\n", tbuff);
+          return 1;
+        }
+
+      mips_expect (" = ");
+
+      /* Lead in the hex number we are expecting: */
+      tbuff[0] = '0';
+      tbuff[1] = 'x';
+
+      /* FIXME!! only 8 bytes!  need to expand for Bfd64; 
+         which targets return 64-bit addresses?  PMON returns only 32! */
+      if (!mips_getstring (&tbuff[2], 8))
+        return 1;
+      tbuff[10] = '\0'; /* terminate the string */
+
+      if (sscanf (tbuff, "0x%08x", &bpaddr) != 1)
+        {
+          fprintf_unfiltered (stderr, "Invalid hex address from target: %s\n", tbuff);
+          return 1;
+        }
+
+      if (bpnum >= PMON_MAX_BP)
+        {
+          fprintf_unfiltered (stderr, "Error: Returned breakpoint number %d outside acceptable range (0..%d)\n",
+                              bpnum, PMON_MAX_BP - 1);
+          return 1;
+        }
+
+      if (bpaddr != addr)
+        fprintf_unfiltered (stderr, "Warning: Breakpoint addresses do not match: 0x%x != 0x%x\n", addr, bpaddr);
+
+      mips_pmon_bp_info[bpnum] = bpaddr;
+
+      mips_expect ("\r\n");
+      mips_expect (mips_monitor_prompt);
+
+      mips_enter_debug ();
+
+      return 0;
+    }
+
+  return mips_store_word (addr, BREAK_INSN, contents_cache);
+}
+
+static int
+pmon_remove_breakpoint (addr, contents_cache)
+     CORE_ADDR addr;
+     char *contents_cache;
+{
+  if (monitor_supports_breakpoints)
+    {
+      int bpnum;
+      char tbuff[7]; /* enough for delete breakpoint command */
+
+      for (bpnum = 0; bpnum < PMON_MAX_BP; bpnum++)
+        if (mips_pmon_bp_info[bpnum] == addr)
+          break;
+
+      if (bpnum >= PMON_MAX_BP)
+        {
+          fprintf_unfiltered (stderr,
+           "pmon_remove_breakpoint: Failed to find breakpoint at address 0x%s\n",
+           paddr_nz (addr));
+          return 1;
+        }
+
+      if (mips_exit_debug ())
+        mips_error ("Failed to exit debug mode");
+
+      sprintf (tbuff, "db %02d\r", bpnum);
+
+      mips_send_command (tbuff, -1);
+      /* NOTE: If the breakpoint does not exist then a "Bpt <dd> not
+         set" message will be returned. */
+
+      mips_enter_debug ();
+
+      return 0;
+    }
+
+  return target_write_memory (addr, contents_cache, BREAK_INSN_SIZE);
+}
+#endif
+
+
+/* Tell whether this target can support a hardware breakpoint.  CNT
+   is the number of hardware breakpoints already installed.  This
+   implements the TARGET_CAN_USE_HARDWARE_WATCHPOINT macro.  */
+
+int
+remote_mips_can_use_hardware_watchpoint (cnt)
+     int cnt;
+{
+    return cnt < MAX_LSI_BREAKPOINTS && strcmp (target_shortname, "lsi") == 0;
+}
+
+
+/* Compute a don't care mask for the region bounding ADDR and ADDR + LEN - 1.
+   This is used for memory ref breakpoints.  */
+
+static unsigned long
+calculate_mask (addr, len)
+     CORE_ADDR addr;
+     int len;
+{
+  unsigned long mask;
+  int i;
+
+  mask = addr ^ (addr + len - 1);
+
+  for (i = 32; i >= 0; i--)
+    if (mask == 0)
+      break;
+    else
+      mask >>= 1;
+
+  mask = (unsigned long) 0xffffffff >> i;
+
+  return mask;
+}
+
+/* Set a data watchpoint.  ADDR and LEN should be obvious.  TYPE is 0
+   for a write watchpoint, 1 for a read watchpoint, or 2 for a read/write
+   watchpoint. */
+
+int
+remote_mips_set_watchpoint (addr, len, type)
+     CORE_ADDR addr;
+     int len;
+     int type;
+{
+  if (set_breakpoint (addr, len, type))
+    return -1;
+
+  return 0;
+}
+
+int
+remote_mips_remove_watchpoint (addr, len, type)
+     CORE_ADDR addr;
+     int len;
+     int type;
+{
+  if (clear_breakpoint (addr, len, type))
+    return -1;
+
+  return 0;
+}
+
+int
+remote_mips_stopped_by_watchpoint ()
+{
+  return hit_watchpoint;
+}
+
+
+/* Insert a breakpoint.  */
+
+static int
+set_breakpoint (addr, len, type)
+     CORE_ADDR addr;
+     int len;
+     enum break_type type;
+{
+  return common_breakpoint (1, addr, len, type);
+}
+
+
+/* Clear a breakpoint.  */
+
+static int
+clear_breakpoint (addr, len, type)
+     CORE_ADDR addr;
+     int len;
+     enum break_type type;
+{
+  return common_breakpoint (0, addr, len, type);
+}
+
+
+/* Check the error code from the return packet for an LSI breakpoint
+   command.  If there's no error, just return 0.  If it's a warning,
+   print the warning text and return 0.  If it's an error, print
+   the error text and return 1.  <ADDR> is the address of the breakpoint
+   that was being set.  <RERRFLG> is the error code returned by PMON. 
+   This is a helper function for common_breakpoint.  */
+
+static int
+check_lsi_error (addr, rerrflg)
+     CORE_ADDR addr;
+     int rerrflg;
+{
+  struct lsi_error *err;
+  char *saddr = paddr_nz (addr);       /* printable address string */
+
+  if (rerrflg == 0)            /* no error */
+    return 0;
+
+  /* Warnings can be ORed together, so check them all.  */
+  if (rerrflg & W_WARN)
+    {
+      if (monitor_warnings)
+       {
+         int found = 0;
+         for (err = lsi_warning_table; err->code != 0; err++)
+           {
+             if ((err->code & rerrflg) == err->code)
+               {
+                 found = 1;
+                 fprintf_unfiltered (stderr,
+                                     "common_breakpoint (0x%s): Warning: %s\n",
+                                     saddr,
+                                     err->string);
+               }
+           }
+         if (!found)
+           fprintf_unfiltered (stderr,
+                               "common_breakpoint (0x%s): Unknown warning: 0x%x\n",
+                               saddr,
+                               rerrflg);
+       }
+      return 0;
+    }
+
+  /* Errors are unique, i.e. can't be ORed together.  */
+  for (err = lsi_error_table; err->code != 0; err++)
+    {
+      if ((err->code & rerrflg) == err->code)
+       {
+         fprintf_unfiltered (stderr,
+                             "common_breakpoint (0x%s): Error: %s\n",
+                             saddr,
+                             err->string);
+         return 1;
+       }
+    }
+  fprintf_unfiltered (stderr,
+                     "common_breakpoint (0x%s): Unknown error: 0x%x\n",
+                     saddr,
+                     rerrflg);
+  return 1;
+}
+
+
+/* This routine sends a breakpoint command to the remote target.
+
+   <SET> is 1 if setting a breakpoint, or 0 if clearing a breakpoint.
+   <ADDR> is the address of the breakpoint.
+   <LEN> the length of the region to break on.
+   <TYPE> is the type of breakpoint:
+     0 = write                 (BREAK_WRITE)
+     1 = read                  (BREAK_READ)
+     2 = read/write            (BREAK_ACCESS)
+     3 = instruction fetch     (BREAK_FETCH)
+
+   Return 0 if successful; otherwise 1.  */
+
+static int
+common_breakpoint (set, addr, len, type)
+     int set;
+     CORE_ADDR addr;
+     int len;
+     enum break_type type;
+{
+  char buf[DATA_MAXLEN + 1];
+  char cmd, rcmd;
+  int rpid, rerrflg, rresponse, rlen;
+  int nfields;
+
+  addr = ADDR_BITS_REMOVE (addr);
+
+  if (mips_monitor == MON_LSI)
+    {
+      if (set == 0)    /* clear breakpoint */
+       {
+         /* The LSI PMON "clear breakpoint" has this form:
+              <pid> 'b' <bptn> 0x0
+              reply:
+              <pid> 'b' 0x0 <code>
+
+            <bptn> is a breakpoint number returned by an earlier 'B' command.
+            Possible return codes: OK, E_BPT.  */
+
+         int i;
+
+         /* Search for the breakpoint in the table.  */
+         for (i = 0; i < MAX_LSI_BREAKPOINTS; i++)
+           if (lsi_breakpoints[i].type == type
+               && lsi_breakpoints[i].addr == addr
+               && lsi_breakpoints[i].len == len)
+             break;
+
+         /* Clear the table entry and tell PMON to clear the breakpoint.  */
+         if (i == MAX_LSI_BREAKPOINTS)
+           {
+             warning ("common_breakpoint: Attempt to clear bogus breakpoint at %s\n",
+                      paddr_nz (addr));
+             return 1;
+           }
+
+         lsi_breakpoints[i].type = BREAK_UNUSED;
+         sprintf (buf, "0x0 b 0x%x 0x0", i);
+         mips_send_packet (buf, 1);
+
+         rlen = mips_receive_packet (buf, 1, mips_receive_wait);
+         buf[rlen] = '\0';
+
+         nfields = sscanf (buf, "0x%x b 0x0 0x%x", &rpid, &rerrflg);
+         if (nfields != 2)
+           mips_error ("common_breakpoint: Bad response from remote board: %s", buf);
+
+         return (check_lsi_error (addr, rerrflg));
+       }
+      else     /* set a breakpoint */
+       {
+         /* The LSI PMON "set breakpoint" command has this form:
+              <pid> 'B' <addr> 0x0
+              reply:
+              <pid> 'B' <bptn> <code>
+
+            The "set data breakpoint" command has this form:
+
+               <pid> 'A' <addr1> <type> [<addr2>  [<value>]]
+
+               where: type= "0x1" = read
+                    "0x2" = write
+                    "0x3" = access (read or write)
+
+            The reply returns two values:
+                    bptn - a breakpoint number, which is a small integer with
+                           possible values of zero through 255.
+                    code - an error return code, a value of zero indicates a
+                           succesful completion, other values indicate various
+                           errors and warnings.
+             
+            Possible return codes: OK, W_QAL, E_QAL, E_OUT, E_NON.  
+
+         */
+
+         if (type == BREAK_FETCH)      /* instruction breakpoint */
+           {
+             cmd = 'B';
+             sprintf (buf, "0x0 B 0x%s 0x0", paddr_nz (addr));
+           }
+         else                          /* watchpoint */
+           {
+             cmd = 'A';
+             sprintf (buf, "0x0 A 0x%s 0x%x 0x%s", paddr_nz (addr),
+                      type == BREAK_READ ? 1 : (type == BREAK_WRITE ? 2 : 3),
+                      paddr_nz (addr + len - 1));
+           }
+         mips_send_packet (buf, 1);
+
+         rlen = mips_receive_packet (buf, 1, mips_receive_wait);
+         buf[rlen] = '\0';
+
+         nfields = sscanf (buf, "0x%x %c 0x%x 0x%x",
+                           &rpid, &rcmd, &rresponse, &rerrflg);
+         if (nfields != 4 || rcmd != cmd || rresponse > 255)
+           mips_error ("common_breakpoint: Bad response from remote board: %s", buf);
+
+         if (rerrflg != 0)
+           if (check_lsi_error (addr, rerrflg))
+             return 1;
+
+         /* rresponse contains PMON's breakpoint number.  Record the
+            information for this breakpoint so we can clear it later.  */
+         lsi_breakpoints[rresponse].type = type;
+         lsi_breakpoints[rresponse].addr = addr;
+         lsi_breakpoints[rresponse].len =  len;
+
+         return 0;
+       }
+    }
+  else
+    {
+      /* On non-LSI targets, the breakpoint command has this form:
+          0x0 <CMD> <ADDR> <MASK> <FLAGS>
+        <MASK> is a don't care mask for addresses.
+        <FLAGS> is any combination of `r', `w', or `f' for read/write/fetch.
+       */
+      unsigned long mask;
+
+      mask = calculate_mask (addr, len);
+      addr &= ~mask;
+
+      if (set)         /* set a breakpoint */
+        {
+         char *flags;
+         switch (type)
+           {
+           case BREAK_WRITE:           /* write */
+             flags = "w";
+             break;
+           case BREAK_READ:            /* read */
+             flags = "r";
+             break;
+           case BREAK_ACCESS:          /* read/write */
+             flags = "rw";
+             break;
+           default:
+             abort ();
+           }
+
+         cmd = 'B';
+         sprintf (buf, "0x0 B 0x%s 0x%s %s", paddr_nz (addr),
+                  paddr_nz (mask), flags);
+       }
+      else
+       {
+         cmd = 'b';
+         sprintf (buf, "0x0 b 0x%s", paddr_nz (addr));
+       }
+
+      mips_send_packet (buf, 1);
+
+      rlen = mips_receive_packet (buf, 1, mips_receive_wait);
+      buf[rlen] = '\0';
+
+      nfields = sscanf (buf, "0x%x %c 0x%x 0x%x",
+                       &rpid, &rcmd, &rerrflg, &rresponse);
+
+      if (nfields != 4 || rcmd != cmd)
+       mips_error ("common_breakpoint: Bad response from remote board: %s",
+                   buf);
+
+      if (rerrflg != 0)
+       {
+         /* Ddb returns "0x0 b 0x16 0x0\000", whereas
+            Cogent returns "0x0 b 0xffffffff 0x16\000": */
+         if (mips_monitor == MON_DDB)
+           rresponse = rerrflg;
+         if (rresponse != 22) /* invalid argument */
+           fprintf_unfiltered (stderr, "common_breakpoint (0x%s):  Got error: 0x%x\n",
+                               paddr_nz (addr), rresponse);
+         return 1;
+       }
+    }
+  return 0;
+}
+\f
+static void
+send_srec (srec, len, addr)
+     char *srec;
+     int len;
+     CORE_ADDR addr;
+{
+  while (1)
+    {
+      int ch;
+
+      SERIAL_WRITE (mips_desc, srec, len);
+
+      ch = mips_readchar (2);
+
+      switch (ch)
+       {
+       case SERIAL_TIMEOUT:
+         error ("Timeout during download.");
+         break;
+       case 0x6:               /* ACK */
+         return;
+       case 0x15:              /* NACK */
+         fprintf_unfiltered (gdb_stderr, "Download got a NACK at byte %d!  Retrying.\n", addr);
+         continue;
+       default:
+         error ("Download got unexpected ack char: 0x%x, retrying.\n", ch);
+       }
+    }
+}
+
+/*  Download a binary file by converting it to S records. */
+
+static void
+mips_load_srec (args)
+     char *args;
+{
+  bfd *abfd;
+  asection *s;
+  char *buffer, srec[1024];
+  unsigned int i;
+  unsigned int srec_frame = 200;
+  int reclen;
+  static int hashmark = 1;
+
+  buffer = alloca (srec_frame * 2 + 256);
+
+  abfd = bfd_openr (args, 0);
+  if (!abfd)
+    {
+      printf_filtered ("Unable to open file %s\n", args);
+      return;
+    }
+
+  if (bfd_check_format (abfd, bfd_object) == 0)
+    {
+      printf_filtered ("File is not an object file\n");
+      return;
+    }
+
+/* This actually causes a download in the IDT binary format: */
+  mips_send_command (LOAD_CMD, 0);
+
+  for (s = abfd->sections; s; s = s->next)
+    {
+      if (s->flags & SEC_LOAD)
+       {
+         unsigned int numbytes;
+
+         /* FIXME!  vma too small?? */
+         printf_filtered ("%s\t: 0x%4x .. 0x%4x  ", s->name, s->vma,
+                          s->vma + s->_raw_size);
+         gdb_flush (gdb_stdout);
+
+         for (i = 0; i < s->_raw_size; i += numbytes)
+           {
+             numbytes = min (srec_frame, s->_raw_size - i);
+
+             bfd_get_section_contents (abfd, s, buffer, i, numbytes);
+
+             reclen = mips_make_srec (srec, '3', s->vma + i, buffer, numbytes);
+             send_srec (srec, reclen, s->vma + i);
+
+             if (hashmark)
+               {
+                 putchar_unfiltered ('#');
+                 gdb_flush (gdb_stdout);
+               }
+
+           } /* Per-packet (or S-record) loop */
+         
+         putchar_unfiltered ('\n');
+       } /* Loadable sections */
+    }
+  if (hashmark) 
+    putchar_unfiltered ('\n');
+  
+  /* Write a type 7 terminator record. no data for a type 7, and there
+     is no data, so len is 0.  */
+
+  reclen = mips_make_srec (srec, '7', abfd->start_address, NULL, 0);
+
+  send_srec (srec, reclen, abfd->start_address);
+
+  SERIAL_FLUSH_INPUT (mips_desc);
+}
+
+/*
+ * mips_make_srec -- make an srecord. This writes each line, one at a
+ *     time, each with it's own header and trailer line.
+ *     An srecord looks like this:
+ *
+ * byte count-+     address
+ * start ---+ |        |       data        +- checksum
+ *         | |        |                   |
+ *       S01000006F6B692D746573742E73726563E4
+ *       S315000448600000000000000000FC00005900000000E9
+ *       S31A0004000023C1400037DE00F023604000377B009020825000348D
+ *       S30B0004485A0000000000004E
+ *       S70500040000F6
+ *
+ *     S<type><length><address><data><checksum>
+ *
+ *      Where
+ *      - length
+ *        is the number of bytes following upto the checksum. Note that
+ *        this is not the number of chars following, since it takes two
+ *        chars to represent a byte.
+ *      - type
+ *        is one of:
+ *        0) header record
+ *        1) two byte address data record
+ *        2) three byte address data record
+ *        3) four byte address data record
+ *        7) four byte address termination record
+ *        8) three byte address termination record
+ *        9) two byte address termination record
+ *       
+ *      - address
+ *        is the start address of the data following, or in the case of
+ *        a termination record, the start address of the image
+ *      - data
+ *        is the data.
+ *      - checksum
+ *       is the sum of all the raw byte data in the record, from the length
+ *        upwards, modulo 256 and subtracted from 255.
+ *
+ * This routine returns the length of the S-record.
+ *
+ */
+
+static int
+mips_make_srec (buf, type, memaddr, myaddr, len)
+     char *buf;
+     int type;
+     CORE_ADDR memaddr;
+     unsigned char *myaddr;
+     int len;
+{
+  unsigned char checksum;
+  int i;
+
+  /* Create the header for the srec. addr_size is the number of bytes in the address,
+     and 1 is the number of bytes in the count.  */
+
+  /* FIXME!! bigger buf required for 64-bit! */
+  buf[0] = 'S';
+  buf[1] = type;
+  buf[2] = len + 4 + 1;                /* len + 4 byte address + 1 byte checksum */
+  /* This assumes S3 style downloads (4byte addresses). There should
+     probably be a check, or the code changed to make it more
+     explicit. */
+  buf[3] = memaddr >> 24;
+  buf[4] = memaddr >> 16;
+  buf[5] = memaddr >> 8;
+  buf[6] = memaddr;
+  memcpy (&buf[7], myaddr, len);
+
+  /* Note that the checksum is calculated on the raw data, not the
+     hexified data.  It includes the length, address and the data
+     portions of the packet.  */
+  checksum = 0;
+  buf += 2;                    /* Point at length byte */
+  for (i = 0; i < len + 4 + 1; i++)
+    checksum += *buf++;
+
+  *buf = ~checksum;
+
+  return len + 8;
+}
+
+/* The following manifest controls whether we enable the simple flow
+   control support provided by the monitor. If enabled the code will
+   wait for an affirmative ACK between transmitting packets. */
+#define DOETXACK (1)
+
+/* The PMON fast-download uses an encoded packet format constructed of
+   3byte data packets (encoded as 4 printable ASCII characters), and
+   escape sequences (preceded by a '/'):
+
+       'K'     clear checksum
+       'C'     compare checksum (12bit value, not included in checksum calculation)
+       'S'     define symbol name (for addr) terminated with "," and padded to 4char boundary
+       'Z'     zero fill multiple of 3bytes
+       'B'     byte (12bit encoded value, of 8bit data)
+       'A'     address (36bit encoded value)
+       'E'     define entry as original address, and exit load
+
+   The packets are processed in 4 character chunks, so the escape
+   sequences that do not have any data (or variable length data)
+   should be padded to a 4 character boundary.  The decoder will give
+   an error if the complete message block size is not a multiple of
+   4bytes (size of record).
+
+   The encoding of numbers is done in 6bit fields.  The 6bit value is
+   used to index into this string to get the specific character
+   encoding for the value: */
+static char encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,.";
+
+/* Convert the number of bits required into an encoded number, 6bits
+   at a time (range 0..63).  Keep a checksum if required (passed
+   pointer non-NULL). The function returns the number of encoded
+   characters written into the buffer. */
+static int
+pmon_makeb64 (v, p, n, chksum)
+     unsigned long v;
+     char *p;
+     int n;
+     int *chksum;
+{
+  int count = (n / 6);
+
+  if ((n % 12) != 0) {
+    fprintf_unfiltered(stderr,"Fast encoding bitcount must be a multiple of 12bits: %dbit%s\n",n,(n == 1)?"":"s");
+    return(0);
+  }
+  if (n > 36) {
+    fprintf_unfiltered(stderr,"Fast encoding cannot process more than 36bits at the moment: %dbits\n",n);
+    return(0);
+  }
+
+  /* Deal with the checksum: */
+  if (chksum != NULL) {
+    switch (n) {
+     case 36: *chksum += ((v >> 24) & 0xFFF);
+     case 24: *chksum += ((v >> 12) & 0xFFF);
+     case 12: *chksum += ((v >>  0) & 0xFFF);
+    }
+  }
+
+  do {
+    n -= 6;
+    *p++ = encoding[(v >> n) & 0x3F];
+  } while (n > 0);
+
+  return(count);
+}
+
+/* Shorthand function (that could be in-lined) to output the zero-fill
+   escape sequence into the data stream. */
+static int
+pmon_zeroset (recsize, buff, amount, chksum)
+     int recsize;
+     char **buff;
+     int *amount;
+     unsigned int *chksum;
+{
+  int count;
+
+  sprintf(*buff,"/Z");
+  count = pmon_makeb64 (*amount, (*buff + 2), 12, chksum);
+  *buff += (count + 2);
+  *amount = 0;
+  return(recsize + count + 2);
+}
+
+static int
+pmon_checkset (recsize, buff, value)
+     int recsize;
+     char **buff;
+     int *value;
+{
+  int count;
+
+  /* Add the checksum (without updating the value): */
+  sprintf (*buff, "/C");
+  count = pmon_makeb64 (*value, (*buff + 2), 12, NULL);
+  *buff += (count + 2);
+  sprintf (*buff, "\n");
+  *buff += 2; /* include zero terminator */
+  /* Forcing a checksum validation clears the sum: */
+  *value = 0;
+  return(recsize + count + 3);
+}
+
+/* Amount of padding we leave after at the end of the output buffer,
+   for the checksum and line termination characters: */
+#define CHECKSIZE (4 + 4 + 4 + 2)
+/* zero-fill, checksum, transfer end and line termination space. */
+
+/* The amount of binary data loaded from the object file in a single
+   operation: */
+#define BINCHUNK (1024)
+
+/* Maximum line of data accepted by the monitor: */
+#define MAXRECSIZE (550)
+/* NOTE: This constant depends on the monitor being used. This value
+   is for PMON 5.x on the Cogent Vr4300 board. */
+
+static void
+pmon_make_fastrec (outbuf, inbuf, inptr, inamount, recsize, csum, zerofill)
+     char **outbuf;
+     unsigned char *inbuf;
+     int *inptr;
+     int inamount;
+     int *recsize;
+     unsigned int *csum;
+     unsigned int *zerofill;
+{
+  int count = 0;
+  char *p = *outbuf;
+
+  /* This is a simple check to ensure that our data will fit within
+     the maximum allowable record size. Each record output is 4bytes
+     in length. We must allow space for a pending zero fill command,
+     the record, and a checksum record. */
+  while ((*recsize < (MAXRECSIZE - CHECKSIZE)) && ((inamount - *inptr) > 0)) {
+    /* Process the binary data: */
+    if ((inamount - *inptr) < 3) {
+      if (*zerofill != 0)
+       *recsize = pmon_zeroset (*recsize, &p, zerofill, csum);
+      sprintf (p, "/B");
+      count = pmon_makeb64 (inbuf[*inptr], &p[2], 12, csum);
+      p += (2 + count);
+      *recsize += (2 + count);
+      (*inptr)++;
+    } else {
+      unsigned int value = ((inbuf[*inptr + 0] << 16) | (inbuf[*inptr + 1] << 8) | inbuf[*inptr + 2]);
+      /* Simple check for zero data. TODO: A better check would be
+         to check the last, and then the middle byte for being zero
+         (if the first byte is not). We could then check for
+         following runs of zeros, and if above a certain size it is
+         worth the 4 or 8 character hit of the byte insertions used
+         to pad to the start of the zeroes. NOTE: This also depends
+         on the alignment at the end of the zero run. */
+      if (value == 0x00000000) {
+        (*zerofill)++;
+        if (*zerofill == 0xFFF) /* 12bit counter */
+         *recsize = pmon_zeroset (*recsize, &p, zerofill, csum);
+      }else {
+        if (*zerofill != 0)
+         *recsize = pmon_zeroset (*recsize, &p, zerofill, csum);
+        count = pmon_makeb64 (value, p, 24, csum);
+        p += count;
+        *recsize += count;
+      }
+      *inptr += 3;
+    }
+  }
+
+  *outbuf = p;
+  return;
+}
+
+static int
+pmon_check_ack(mesg)
+     char *mesg;
+{
+#if defined(DOETXACK)
+  int c;
+
+  if (!tftp_in_use)
+    {
+      c = SERIAL_READCHAR (udp_in_use ? udp_desc : mips_desc, 2);
+      if ((c == SERIAL_TIMEOUT) || (c != 0x06))
+       {
+         fprintf_unfiltered (gdb_stderr,
+                             "Failed to receive valid ACK for %s\n", mesg);
+         return(-1); /* terminate the download */
+       }
+    }
+#endif /* DOETXACK */
+  return(0);
+}
+
+/* pmon_download - Send a sequence of characters to the PMON download port,
+   which is either a serial port or a UDP socket.  */
+
+static void
+pmon_start_download ()
+{
+  if (tftp_in_use)
+    {
+      /* Create the temporary download file.  */
+      if ((tftp_file = fopen (tftp_localname, "w")) == NULL)
+       perror_with_name (tftp_localname);
+    }
+  else
+    {
+      mips_send_command (udp_in_use ? LOAD_CMD_UDP : LOAD_CMD, 0);
+      mips_expect ("Downloading from ");
+      mips_expect (udp_in_use ? "udp" : "tty0");
+      mips_expect (", ^C to abort\r\n");
+    }
+}
+
+static int
+mips_expect_download (char *string)
+{
+  if (!mips_expect (string))
+    {
+      fprintf_unfiltered (gdb_stderr, "Load did not complete successfully.\n");
+      if (tftp_in_use)
+       remove (tftp_localname);        /* Remove temporary file */
+      return 0;
+    }
+  else
+    return 1;
+}
+
+static void
+pmon_end_download (final, bintotal)
+     int final;
+     int bintotal;
+{
+  char hexnumber[9]; /* includes '\0' space */
+
+  if (tftp_in_use)
+    {
+      static char *load_cmd_prefix = "load -b -s ";
+      char *cmd;
+      struct stat stbuf;
+
+      /* Close off the temporary file containing the load data.  */
+      fclose (tftp_file);
+      tftp_file = NULL;
+
+      /* Make the temporary file readable by the world.  */
+      if (stat (tftp_localname, &stbuf) == 0)
+       chmod (tftp_localname, stbuf.st_mode | S_IROTH);
+
+      /* Must reinitialize the board to prevent PMON from crashing.  */
+      mips_send_command ("initEther\r", -1);
+
+      /* Send the load command.  */
+      cmd = xmalloc (strlen (load_cmd_prefix) + strlen (tftp_name) + 2);
+      strcpy (cmd, load_cmd_prefix);
+      strcat (cmd, tftp_name);
+      strcat (cmd, "\r");
+      mips_send_command (cmd, 0);
+      free (cmd);
+      if (!mips_expect_download ("Downloading from "))
+       return;
+      if (!mips_expect_download (tftp_name))
+       return;
+      if (!mips_expect_download (", ^C to abort\r\n"))
+       return;
+    }
+
+  /* Wait for the stuff that PMON prints after the load has completed.
+     The timeout value for use in the tftp case (15 seconds) was picked
+     arbitrarily but might be too small for really large downloads. FIXME. */
+  if (mips_monitor == MON_LSI)
+    {
+      pmon_check_ack ("termination");
+      mips_expect_timeout ("Entry address is ", tftp_in_use ? 15 : 2);
+    }
+  else
+    mips_expect_timeout ("Entry Address  = ", tftp_in_use ? 15 : 2);
+
+  sprintf (hexnumber,"%x",final);
+  mips_expect (hexnumber);
+  mips_expect ("\r\n");
+  if (mips_monitor != MON_LSI)
+    pmon_check_ack ("termination");
+  mips_expect ("\r\ntotal = 0x");
+  sprintf (hexnumber,"%x",bintotal);
+  mips_expect (hexnumber);
+  if (!mips_expect_download (" bytes\r\n"))
+    return;
+
+  if (tftp_in_use)
+    remove (tftp_localname);   /* Remove temporary file */
+}
+
+static void
+pmon_download (buffer, length)
+     char *buffer;
+     int length;
+{
+  if (tftp_in_use)
+    fwrite (buffer, 1, length, tftp_file);
+  else
+    SERIAL_WRITE (udp_in_use ? udp_desc : mips_desc, buffer, length);
+}
+
+static void
+pmon_load_fast (file)
+     char *file;
+{
+  bfd *abfd;
+  asection *s;
+  unsigned char *binbuf;
+  char *buffer;
+  int reclen;
+  unsigned int csum = 0;
+  int hashmark = !tftp_in_use;
+  int bintotal = 0;
+  int final = 0;
+  int finished = 0;
+
+  buffer = (char *)xmalloc(MAXRECSIZE + 1);
+  binbuf = (unsigned char *)xmalloc(BINCHUNK);
+
+  abfd = bfd_openr(file,0);
+  if (!abfd)
+   {
+     printf_filtered ("Unable to open file %s\n",file);
+     return;
+   }
+
+  if (bfd_check_format(abfd,bfd_object) == 0)
+   {
+     printf_filtered("File is not an object file\n");
+     return;
+   }
+
+  /* Setup the required download state: */
+  mips_send_command ("set dlproto etxack\r", -1);
+  mips_send_command ("set dlecho off\r", -1);
+  /* NOTE: We get a "cannot set variable" message if the variable is
+     already defined to have the argument we give. The code doesn't
+     care, since it just scans to the next prompt anyway. */
+  /* Start the download: */
+  pmon_start_download();
+  
+  /* Zero the checksum */
+  sprintf(buffer,"/Kxx\n");
+  reclen = strlen(buffer);
+  pmon_download (buffer, reclen);
+  finished = pmon_check_ack("/Kxx");
+
+  for (s = abfd->sections; s && !finished; s = s->next)
+   if (s->flags & SEC_LOAD) /* only deal with loadable sections */
+    {
+      bintotal += s->_raw_size;
+      final = (s->vma + s->_raw_size);
+
+      printf_filtered ("%s\t: 0x%4x .. 0x%4x  ", s->name, (unsigned int)s->vma,
+                       (unsigned int)(s->vma + s->_raw_size));
+      gdb_flush (gdb_stdout);
+
+      /* Output the starting address */
+      sprintf(buffer,"/A");
+      reclen = pmon_makeb64(s->vma,&buffer[2],36,&csum);
+      buffer[2 + reclen] = '\n';
+      buffer[3 + reclen] = '\0';
+      reclen += 3; /* for the initial escape code and carriage return */
+      pmon_download (buffer, reclen);
+      finished = pmon_check_ack("/A");
+
+      if (!finished)
+       {
+         unsigned int binamount;
+         unsigned int zerofill = 0;
+         char *bp = buffer;
+         unsigned int i;
+
+         reclen = 0;
+
+         for (i = 0; ((i < s->_raw_size) && !finished); i += binamount) {
+           int binptr = 0;
+
+           binamount = min (BINCHUNK, s->_raw_size - i);
+
+           bfd_get_section_contents (abfd, s, binbuf, i, binamount);
+
+           /* This keeps a rolling checksum, until we decide to output
+              the line: */
+           for (; ((binamount - binptr) > 0);) {
+             pmon_make_fastrec (&bp, binbuf, &binptr, binamount, &reclen, &csum, &zerofill);
+             if (reclen >= (MAXRECSIZE - CHECKSIZE)) {
+               reclen = pmon_checkset (reclen, &bp, &csum);
+               pmon_download (buffer, reclen);
+               finished = pmon_check_ack("data record");
+               if (finished) {
+                 zerofill = 0; /* do not transmit pending zerofills */
+                 break;
+               }
+
+               if (hashmark) {
+                 putchar_unfiltered ('#');
+                 gdb_flush (gdb_stdout);
+               }
+
+               bp = buffer;
+               reclen = 0; /* buffer processed */
+             }
+           }
+         }
+
+         /* Ensure no out-standing zerofill requests: */
+         if (zerofill != 0)
+          reclen = pmon_zeroset (reclen, &bp, &zerofill, &csum);
+
+         /* and then flush the line: */
+         if (reclen > 0) {
+           reclen = pmon_checkset (reclen, &bp, &csum);
+           /* Currently pmon_checkset outputs the line terminator by
+              default, so we write out the buffer so far: */
+           pmon_download (buffer, reclen);
+           finished = pmon_check_ack("record remnant");
+         }
+       }
+
+      putchar_unfiltered ('\n');
+    }
+
+  /* Terminate the transfer. We know that we have an empty output
+     buffer at this point. */
+  sprintf (buffer, "/E/E\n"); /* include dummy padding characters */
+  reclen = strlen (buffer);
+  pmon_download (buffer, reclen);
+
+  if (finished) { /* Ignore the termination message: */
+    SERIAL_FLUSH_INPUT (udp_in_use ? udp_desc : mips_desc);
+  } else { /* Deal with termination message: */
+    pmon_end_download (final, bintotal);
+  }
+
+  return;
+}
+
+/* mips_load -- download a file. */
+
+static void
+mips_load (file, from_tty)
+    char *file;
+    int  from_tty;
+{
+  /* Get the board out of remote debugging mode.  */
+  if (mips_exit_debug ())
+    error ("mips_load:  Couldn't get into monitor mode.");
+
+  if (mips_monitor != MON_IDT)
+   pmon_load_fast (file);
+  else
+   mips_load_srec (file);
+
+  mips_initialize ();
+
+  /* Finally, make the PC point at the start address */
+  if (mips_monitor != MON_IDT)
+    {
+      /* Work around problem where PMON monitor updates the PC after a load
+        to a different value than GDB thinks it has. The following ensures
+        that the write_pc() WILL update the PC value: */
+      register_valid[PC_REGNUM] = 0;
+    }
+  if (exec_bfd)
+    write_pc (bfd_get_start_address (exec_bfd));
+
+  inferior_pid = 0;            /* No process now */
+
+/* This is necessary because many things were based on the PC at the time that
+   we attached to the monitor, which is no longer valid now that we have loaded
+   new code (and just changed the PC).  Another way to do this might be to call
+   normal_stop, except that the stack may not be valid, and things would get
+   horribly confused... */
+
+  clear_symtab_users ();
+}
+
+
+/* Pass the command argument as a packet to PMON verbatim.  */
+
+static void
+pmon_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  char buf[DATA_MAXLEN + 1];
+  int rlen;
+
+  sprintf (buf, "0x0 %s", args);
+  mips_send_packet (buf, 1);
+  printf_filtered ("Send packet: %s\n", buf);
+
+  rlen = mips_receive_packet (buf, 1, mips_receive_wait);
+  buf[rlen] = '\0';
+  printf_filtered ("Received packet: %s\n", buf);
+}
 \f
 void
 _initialize_remote_mips ()
 {
+  /* Initialize the fields in mips_ops that are common to all four targets.  */
+  mips_ops.to_longname = "Remote MIPS debugging over serial line";
+  mips_ops.to_close = mips_close;
+  mips_ops.to_detach = mips_detach;
+  mips_ops.to_resume = mips_resume;
+  mips_ops.to_fetch_registers = mips_fetch_registers;
+  mips_ops.to_store_registers = mips_store_registers;
+  mips_ops.to_prepare_to_store = mips_prepare_to_store;
+  mips_ops.to_xfer_memory = mips_xfer_memory;
+  mips_ops.to_files_info = mips_files_info;
+  mips_ops.to_insert_breakpoint = mips_insert_breakpoint;
+  mips_ops.to_remove_breakpoint = mips_remove_breakpoint;
+  mips_ops.to_kill = mips_kill;
+  mips_ops.to_load = mips_load;
+  mips_ops.to_create_inferior = mips_create_inferior;
+  mips_ops.to_mourn_inferior = mips_mourn_inferior;
+  mips_ops.to_stratum = process_stratum;
+  mips_ops.to_has_all_memory = 1;
+  mips_ops.to_has_memory = 1;
+  mips_ops.to_has_stack = 1;
+  mips_ops.to_has_registers = 1;
+  mips_ops.to_has_execution = 1;
+  mips_ops.to_magic = OPS_MAGIC;
+
+  /* Copy the common fields to all four target vectors.  */
+  pmon_ops = ddb_ops = lsi_ops = mips_ops;
+
+  /* Initialize target-specific fields in the target vectors.  */
+  mips_ops.to_shortname = "mips";
+  mips_ops.to_doc = "\
+Debug a board using the MIPS remote debugging protocol over a serial line.\n\
+The argument is the device it is connected to or, if it contains a colon,\n\
+HOST:PORT to access a board over a network";
+  mips_ops.to_open = mips_open;
+  mips_ops.to_wait = mips_wait;
+
+  pmon_ops.to_shortname = "pmon";
+  pmon_ops.to_doc =   "\
+Debug a board using the PMON MIPS remote debugging protocol over a serial\n\
+line. The argument is the device it is connected to or, if it contains a\n\
+colon, HOST:PORT to access a board over a network";
+  pmon_ops.to_open = pmon_open;
+  pmon_ops.to_wait = mips_wait;
+
+  ddb_ops.to_shortname = "ddb";
+  ddb_ops.to_doc = "\
+Debug a board using the PMON MIPS remote debugging protocol over a serial\n\
+line. The first argument is the device it is connected to or, if it contains\n\
+a colon, HOST:PORT to access a board over a network.  The optional second\n\
+parameter is the temporary file in the form HOST:FILENAME to be used for\n\
+TFTP downloads to the board.  The optional third parameter is the local name\n\
+of the TFTP temporary file, if it differs from the filename seen by the board.";
+  ddb_ops.to_open = ddb_open;
+  ddb_ops.to_wait = mips_wait;
+
+  lsi_ops.to_shortname = "lsi";
+  lsi_ops.to_doc = pmon_ops.to_doc;
+  lsi_ops.to_open = lsi_open;
+  lsi_ops.to_wait = mips_wait;
+
+  /* Add the targets.  */
   add_target (&mips_ops);
+  add_target (&pmon_ops);
+  add_target (&ddb_ops);
+  add_target (&lsi_ops);
 
   add_show_from_set (
     add_set_cmd ("timeout", no_class, var_zinteger,
@@ -1396,4 +3583,33 @@ _initialize_remote_mips ()
 This is the number of seconds to wait for an acknowledgement to a packet\n\
 before resending the packet.", &setlist),
        &showlist);
+
+  add_show_from_set (
+    add_set_cmd ("syn-garbage-limit", no_class, var_zinteger,
+                (char *) &mips_syn_garbage,
+"Set the maximum number of characters to ignore when scanning for a SYN.\n\
+This is the maximum number of characters GDB will ignore when trying to\n\
+synchronize with the remote system.  A value of -1 means that there is no limit\n\
+(Note that these characters are printed out even though they are ignored.)",
+                &setlist),
+                    &showlist);
+
+  add_show_from_set
+    (add_set_cmd ("monitor-prompt", class_obscure, var_string,
+                 (char *) &mips_monitor_prompt,
+                 "Set the prompt that GDB expects from the monitor.",
+                 &setlist),
+     &showlist);
+
+  add_show_from_set (
+    add_set_cmd ("monitor-warnings", class_obscure, var_zinteger,
+                (char *)&monitor_warnings,
+                "Set printing of monitor warnings.\n"
+                "When enabled, monitor warnings about hardware breakpoints "
+                "will be displayed.",
+                &setlist),
+                    &showlist);
+
+  add_com ("pmon <command>", class_obscure, pmon_command,
+          "Send a packet to PMON (must be in debug mode)."); 
 }
This page took 0.054418 seconds and 4 git commands to generate.