aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorStu Grossman <grossman@cygnus>1995-10-16 19:02:41 +0000
committerStu Grossman <grossman@cygnus>1995-10-16 19:02:41 +0000
commit4704fd9cab13f8c6f95f02f7fae15ad260e1b5b6 (patch)
treeb6dae58965cd51e5882c0c5aa46917f2326fd277 /gdb
parent59227c078d47b163588f87a95516bf7844c6c8b4 (diff)
downloadgdb-4704fd9cab13f8c6f95f02f7fae15ad260e1b5b6.zip
gdb-4704fd9cab13f8c6f95f02f7fae15ad260e1b5b6.tar.gz
gdb-4704fd9cab13f8c6f95f02f7fae15ad260e1b5b6.tar.bz2
* remote-mips.c: Add support for speedy (about 10x faster)
downloads.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog3
-rw-r--r--gdb/remote-mips.c310
2 files changed, 301 insertions, 12 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e9f44af..c93eb59 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,8 @@
Mon Oct 16 11:27:06 1995 Stu Grossman (grossman@cygnus.com)
+ * remote-mips.c: Add support for speedy (about 10x faster)
+ downloads.
+
* remote-array.c: Move baud_rate initialization from
_initialize_array to array_open. It was forcing the baud rate of
all targets to be 4800 baud! Seems like I've fixed this before...
diff --git a/gdb/remote-mips.c b/gdb/remote-mips.c
index bfbfc53..8761cbf 100644
--- a/gdb/remote-mips.c
+++ b/gdb/remote-mips.c
@@ -100,6 +100,11 @@ static void mips_create_inferior PARAMS ((char *execfile, char *args,
static void mips_mourn_inferior PARAMS ((void));
+static void mips_load PARAMS ((char *file, int from_tty));
+
+static int mips_make_srec PARAMS ((char *buffer, char type, CORE_ADDR memaddr,
+ unsigned char *myaddr, int len));
+
/* A forward declaration. */
extern struct target_ops mips_ops;
@@ -313,6 +318,43 @@ mips_error (va_alist)
return_to_top_level (RETURN_ERROR);
}
+int
+mips_expect (string)
+ char *string;
+{
+ char *p = string;
+ int c;
+
+ immediate_quit = 1;
+ while (1)
+ {
+
+/* Must use SERIAL_READCHAR here cuz mips_readchar would get confused if we
+ were waiting for "<IDT>"... */
+
+ c = SERIAL_READCHAR (mips_desc, 2);
+
+ if (c == SERIAL_TIMEOUT)
+ return 0;
+
+ if (c == *p++)
+ {
+ if (*p == '\0')
+ {
+ immediate_quit = 0;
+
+ return 1;
+ }
+ }
+ else
+ {
+ p = string;
+ if (c == *p)
+ p++;
+ }
+ }
+}
+
/* 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
@@ -568,9 +610,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. */
@@ -591,6 +630,9 @@ mips_send_packet (s, get_ack)
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)
@@ -972,19 +1014,32 @@ mips_initialize ()
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 = '\015';
- /* FIXME check the result from this */
- SERIAL_WRITE (mips_desc, &cr, 1);
-
if (mips_receive_packet (buff, 0, 3) < 0)
{
char cc;
+ int i;
+ char srec[10];
/* We did not receive the packet we expected; try resetting the
board and trying again. */
+
+ /* 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. */
+
+ 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. */
+ }
+
printf_filtered ("Failed to initialize; trying to reset board\n");
cc = '\003';
SERIAL_WRITE (mips_desc, &cc, 1);
@@ -993,8 +1048,9 @@ mips_initialize ()
sleep (1);
cr = '\015';
SERIAL_WRITE (mips_desc, &cr, 1);
+
+ mips_receive_packet (buff, 1, 3);
}
- mips_receive_packet (buff, 1, 3);
do_cleanups (old_cleanups);
@@ -1533,6 +1589,236 @@ mips_remove_breakpoint (addr, contents_cache)
{
return target_write_memory (addr, contents_cache, BREAK_INSN_SIZE);
}
+
+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];
+ int i;
+ 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;
+ }
+
+#define LOAD_CMD "load -b -s tty0\015"
+
+ SERIAL_WRITE (mips_desc, LOAD_CMD, sizeof LOAD_CMD - 1);
+
+ mips_expect (LOAD_CMD);
+ mips_expect ("\012");
+
+ for (s = abfd->sections; s; s = s->next)
+ {
+ if (s->flags & SEC_LOAD)
+ {
+ int numbytes;
+
+ 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;
+ char 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. */
+
+ buf[0] = 'S';
+ buf[1] = type;
+ buf[2] = len + 4 + 1; /* len + 4 byte address + 1 byte checksum */
+ 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;
+}
+
+/* mips_load -- download a file. */
+
+static void
+mips_load (file, from_tty)
+ char *file;
+ int from_tty;
+{
+ int err;
+
+ /* Get the board out of remote debugging mode. */
+
+ mips_request ('x', (unsigned int) 0, (unsigned int) 0, &err,
+ mips_receive_wait);
+
+
+ if (!mips_expect ("\015\012<IDT>"))
+ error ("mips_load: Couldn't get into monitor mode.");
+
+ mips_load_srec (file);
+
+ SERIAL_WRITE (mips_desc, "\015db tty0\015", sizeof "\015db tty0\015" - 1);
+
+ mips_initialize ();
+
+/* Finally, make the PC point at the start address */
+
+ 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 ();
+}
/* The target vector. */
@@ -1563,7 +1849,7 @@ HOST:PORT to access a board over a network", /* to_doc */
NULL, /* to_terminal_ours */
NULL, /* to_terminal_info */
mips_kill, /* to_kill */
- generic_load, /* to_load */
+ mips_load, /* to_load */
NULL, /* to_lookup_symbol */
mips_create_inferior, /* to_create_inferior */
mips_mourn_inferior, /* to_mourn_inferior */