* remote-mips.c: Add support for speedy (about 10x faster)

downloads.
This commit is contained in:
Stu Grossman 1995-10-16 19:02:41 +00:00
parent 59227c078d
commit 4704fd9cab
2 changed files with 301 additions and 12 deletions

View File

@ -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...

View File

@ -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 */