#include "defs.h"
#include "inferior.h"
#include "wait.h"
-#include "value.h"
+
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
+
#include "terminal.h"
-#include "target.h"
#include "gdbcore.h"
-#include "serial.h"
+#include "gdbcmd.h"
+
+#include "remote-utils.h"
+
+extern int sleep();
/* External data declarations */
extern int stop_soon_quietly; /* for wait_for_inferior */
/* Forward data declarations */
-static struct target_ops bug_ops; /* Forward declaration */
+extern struct target_ops bug_ops; /* Forward declaration */
/* Forward function declarations */
-static void bug_fetch_registers ();
-static int bug_store_registers ();
-static void bug_close ();
-static int bug_clear_breakpoints ();
-
-static int quiet = 1;
-
-
-serial_t desc;
-
-/***********************************************************************/
-/* Caching stuff stolen from remote-nindy.c */
-
-/* The data cache records all the data read from the remote machine
- since the last time it stopped.
-
- Each cache block holds LINE_SIZE bytes of data
- starting at a multiple-of-LINE_SIZE address. */
-
-#define LINE_SIZE_POWER 4
-#define LINE_SIZE (1<<LINE_SIZE_POWER) /* eg 1<<3 == 8 */
-#define LINE_SIZE_MASK ((LINE_SIZE-1)) /* eg 7*2+1= 111*/
-#define DCACHE_SIZE 64 /* Number of cache blocks */
-#define XFORM(x) ((x&LINE_SIZE_MASK)>>2)
-struct dcache_block
- {
- struct dcache_block *next, *last;
- unsigned int addr; /* Address for which data is recorded. */
- int data[LINE_SIZE / sizeof (int)];
- };
-
-struct dcache_block dcache_free, dcache_valid;
-
-/* Free all the data cache blocks, thus discarding all cached data. */
-static
-void
-dcache_flush ()
-{
- register struct dcache_block *db;
-
- while ((db = dcache_valid.next) != &dcache_valid)
- {
- remque (db);
- insque (db, &dcache_free);
- }
-}
-
-/*
- * If addr is present in the dcache, return the address of the block
- * containing it.
- */
-static
-struct dcache_block *
-dcache_hit (addr)
- unsigned int addr;
-{
- register struct dcache_block *db;
-
- if (addr & 3)
- abort ();
-
- /* Search all cache blocks for one that is at this address. */
- db = dcache_valid.next;
- while (db != &dcache_valid)
- {
- if ((addr & ~LINE_SIZE_MASK) == db->addr)
- return db;
- db = db->next;
- }
- return NULL;
-}
-
-/* Return the int data at address ADDR in dcache block DC. */
-static
-int
-dcache_value (db, addr)
- struct dcache_block *db;
- unsigned int addr;
-{
- if (addr & 3)
- abort ();
- return (db->data[XFORM (addr)]);
-}
-
-/* Get a free cache block, put or keep it on the valid list,
- and return its address. The caller should store into the block
- the address and data that it describes, then remque it from the
- free list and insert it into the valid list. This procedure
- prevents errors from creeping in if a ninMemGet is interrupted
- (which used to put garbage blocks in the valid list...). */
-static
-struct dcache_block *
-dcache_alloc ()
-{
- register struct dcache_block *db;
-
- if ((db = dcache_free.next) == &dcache_free)
- {
- /* If we can't get one from the free list, take last valid and put
- it on the free list. */
- db = dcache_valid.last;
- remque (db);
- insque (db, &dcache_free);
- }
-
- remque (db);
- insque (db, &dcache_valid);
- return (db);
-}
-
-/* Return the contents of the word at address ADDR in the remote machine,
- using the data cache. */
-static
-int
-dcache_fetch (addr)
- CORE_ADDR addr;
-{
- register struct dcache_block *db;
-
- db = dcache_hit (addr);
- if (db == 0)
- {
- db = dcache_alloc ();
- immediate_quit++;
- bug_read_inferior_memory (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE);
- immediate_quit--;
- db->addr = addr & ~LINE_SIZE_MASK;
- remque (db); /* Off the free list */
- insque (db, &dcache_valid); /* On the valid list */
- }
- return (dcache_value (db, addr));
-}
-
-/* Write the word at ADDR both in the data cache and in the remote machine. */
-static void
-dcache_poke (addr, data)
- CORE_ADDR addr;
- int data;
-{
- register struct dcache_block *db;
-
- /* First make sure the word is IN the cache. DB is its cache block. */
- db = dcache_hit (addr);
- if (db == 0)
- {
- db = dcache_alloc ();
- immediate_quit++;
- bug_write_inferior_memory (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE);
- immediate_quit--;
- db->addr = addr & ~LINE_SIZE_MASK;
- remque (db); /* Off the free list */
- insque (db, &dcache_valid); /* On the valid list */
- }
-
- /* Modify the word in the cache. */
- db->data[XFORM (addr)] = data;
-
- /* Send the changed word. */
- immediate_quit++;
- bug_write_inferior_memory (addr, (unsigned char *) &data, 4);
- immediate_quit--;
-}
-
-/* The cache itself. */
-struct dcache_block the_cache[DCACHE_SIZE];
+static int bug_clear_breakpoints PARAMS((void));
-/* Initialize the data cache. */
-static void
-dcache_init ()
-{
- register i;
- register struct dcache_block *db;
-
- db = the_cache;
- dcache_free.next = dcache_free.last = &dcache_free;
- dcache_valid.next = dcache_valid.last = &dcache_valid;
- for (i = 0; i < DCACHE_SIZE; i++, db++)
- insque (db, &dcache_free);
-}
-
-/***********************************************************************
- * I/O stuff stolen from remote-eb.c
- ***********************************************************************/
-
-static int timeout = 2;
-
-static const char *dev_name;
+static int bug_read_memory PARAMS((CORE_ADDR memaddr,
+ unsigned char *myaddr,
+ int len));
-/* Descriptor for I/O to remote machine. Initialize it to -1 so that
- bug_open knows that we don't have a file open when the program
- starts. */
+static int bug_write_memory PARAMS((CORE_ADDR memaddr,
+ unsigned char *myaddr,
+ int len));
-int is_open = 0;
-int
-check_open ()
-{
- if (!is_open)
- {
- error ("remote device not open");
- }
-}
+/* This variable is somewhat arbitrary. It's here so that it can be
+ set from within a running gdb. */
-#define ON 1
-#define OFF 0
+static int srec_max_retries = 3;
-/* Read a character from the remote system, doing all the fancy
- timeout stuff. */
-static int
-readchar ()
-{
- int buf;
-
- buf = SERIAL_READCHAR (desc, timeout);
-
- if (buf == SERIAL_TIMEOUT)
- error ("Timeout reading from remote system.");
-
- if (!quiet)
- printf ("%c", buf);
-
- return buf & 0x7f;
-}
-
-static int
-readchar_nofail ()
-{
- int buf;
-
- buf = SERIAL_READCHAR (desc, timeout);
- if (buf == SERIAL_TIMEOUT)
- buf = 0;
- if (!quiet)
- printf ("%c", buf);
-
- return buf & 0x7f;
-
-}
-
-/* Keep discarding input from the remote system, until STRING is found.
- Let the user break out immediately. */
-static void
-expect (string)
- char *string;
-{
- char *p = string;
-
- immediate_quit = 1;
- while (1)
- {
- if (readchar () == *p)
- {
- p++;
- if (*p == '\0')
- {
- immediate_quit = 0;
- return;
- }
- }
- else
- p = string;
- }
-}
+/* Each S-record download to the target consists of an S0 header
+ record, some number of S3 data records, and one S7 termination
+ record. I call this download a "frame". Srec_frame says how many
+ bytes will be represented in each frame. */
-/* Keep discarding input until we see the bug prompt.
+#define SREC_SIZE 160
+static int srec_frame = SREC_SIZE;
- The convention for dealing with the prompt is that you
- o give your command
- o *then* wait for the prompt.
+/* This variable determines how many bytes will be represented in each
+ S3 s-record. */
- Thus the last thing that a procedure does with the serial line
- will be an expect_prompt(). Exception: bug_resume does not
- wait for the prompt, because the terminal is being handed over
- to the inferior. However, the next thing which happens after that
- is a bug_wait which does wait for the prompt.
- Note that this includes abnormal exit, e.g. error(). This is
- necessary to prevent getting into states from which we can't
- recover. */
-static void
-expect_prompt ()
-{
- expect ("Bug>");
-}
+static int srec_bytes = 40;
-/* Get a hex digit from the remote system & return its value.
- If ignore_space is nonzero, ignore spaces (not newline, tab, etc). */
-static int
-get_hex_digit (ignore_space)
- int ignore_space;
-{
- int ch;
+/* At one point it appeared to me as though the bug monitor could not
+ really be expected to receive two sequential characters at 9600
+ baud reliably. Echo-pacing is an attempt to force data across the
+ line even in this condition. Specifically, in echo-pace mode, each
+ character is sent one at a time and we look for the echo before
+ sending the next. This is excruciatingly slow. */
- while (1)
- {
- ch = readchar ();
- if (ch >= '0' && ch <= '9')
- return ch - '0';
- else if (ch >= 'A' && ch <= 'F')
- return ch - 'A' + 10;
- else if (ch >= 'a' && ch <= 'f')
- return ch - 'a' + 10;
- else if (ch == ' ' && ignore_space)
- ;
- else
- {
- expect_prompt ();
- error ("Invalid hex digit from remote system.");
- }
- }
-}
+static int srec_echo_pace = 0;
-/* Get a byte from bug_desc and put it in *BYT. Accept any number
- leading spaces. */
-static void
-get_hex_byte (byt)
- char *byt;
-{
- int val;
+/* How long to wait after an srec for a possible error message.
+ Similar to the above, I tried sleeping after sending each S3 record
+ in hopes that I might actually see error messages from the bug
+ monitor. This might actually work if we were to use sleep
+ intervals smaller than 1 second. */
- val = get_hex_digit (1) << 4;
- val |= get_hex_digit (0);
- *byt = val;
-}
+static int srec_sleep = 0;
-/* Read a 32-bit hex word from the bug, preceded by a space */
-static long
-get_hex_word ()
-{
- long val;
- int j;
+/* Every srec_noise records, flub the checksum. This is a debugging
+ feature. Set the variable to something other than 1 in order to
+ inject *deliberate* checksum errors. One might do this if one
+ wanted to test error handling and recovery. */
- val = 0;
- for (j = 0; j < 8; j++)
- val = (val << 4) + get_hex_digit (j == 0);
- return val;
-}
+static int srec_noise = 0;
/* Called when SIGALRM signal sent due to alarm() timeout. */
static int need_artificial_trap = 0;
-void
-bug_kill (arg, from_tty)
- char *arg;
- int from_tty;
-{
-
-}
-
/*
* Download a file specified in 'args', to the bug.
*/
+
static void
bug_load (args, fromtty)
char *args;
{
bfd *abfd;
asection *s;
- int n;
char buffer[1024];
- check_open ();
+ sr_check_open ();
- dcache_flush ();
+ dcache_flush (gr_get_dcache());
inferior_pid = 0;
abfd = bfd_openr (args, 0);
if (!abfd)
s = abfd->sections;
while (s != (asection *) NULL)
{
+ srec_frame = SREC_SIZE;
if (s->flags & SEC_LOAD)
{
int i;
-#define DELTA (1024)
- char *buffer = xmalloc (DELTA);
+ char *buffer = xmalloc (srec_frame);
printf_filtered ("%s\t: 0x%4x .. 0x%4x ", s->name, s->vma, s->vma + s->_raw_size);
- for (i = 0; i < s->_raw_size; i += DELTA)
+ fflush (stdout);
+ for (i = 0; i < s->_raw_size; i += srec_frame)
{
- int delta = DELTA;
-
- if (delta > s->_raw_size - i)
- delta = s->_raw_size - i;
+ if (srec_frame > s->_raw_size - i)
+ srec_frame = s->_raw_size - i;
- bfd_get_section_contents (abfd, s, buffer, i, delta);
- bug_write_inferior_memory (s->vma + i, buffer, delta);
+ bfd_get_section_contents (abfd, s, buffer, i, srec_frame);
+ bug_write_memory (s->vma + i, buffer, srec_frame);
printf_filtered ("*");
fflush (stdout);
}
}
s = s->next;
}
- sprintf (buffer, "rs ip %x", abfd->start_address);
- bug_write_cr (buffer);
- expect_prompt ();
-}
-
-/* This is called not only when we first attach, but also when the
- user types "run" after having attached. */
-void
-bug_create_inferior (execfile, args, env)
- char *execfile;
- char *args;
- char **env;
-{
- int entry_pt;
- char buffer[100];
-
- if (args && *args)
- error ("Can't pass arguments to remote bug process.");
-
- if (execfile == 0 || exec_bfd == 0)
- error ("No exec file specified");
-
- entry_pt = (int) bfd_get_start_address (exec_bfd);
- check_open ();
-
- bug_kill (NULL, NULL);
- bug_clear_breakpoints ();
- init_wait_for_inferior ();
- bug_write_cr ("");
- expect_prompt ();
-
- insert_breakpoints (); /* Needed to get correct instruction in cache */
- proceed (entry_pt, -1, 0);
-}
-
-/* Open a connection to a remote debugger.
- NAME is the filename used for communication, then a space,
- then the baud rate.
- */
-
-static char *
-find_end_of_word (s)
- char *s;
-{
- while (*s && !isspace (*s))
- s++;
- return s;
+ sprintf (buffer, "rs ip %lx", (unsigned long) abfd->start_address);
+ sr_write_cr (buffer);
+ gr_expect_prompt ();
}
+#if 0
static char *
get_word (p)
char **p;
*p = s;
return copy;
}
+#endif
-static int baudrate = 9600;
-
-#if 0
-static int
-is_baudrate_right ()
-{
- int ok;
-
- /* Put this port into NORMAL mode, send the 'normal' character */
-
- bug_write ("\001", 1); /* Control A */
- bug_write ("\r", 1); /* Cr */
-
- while (1)
- {
- ok = SERIAL_READCHAR (desc, timeout);
- if (ok < 0)
- break;
- }
-
- bug_write ("r", 1);
-
- if (readchar_nofail () == 'r')
- return 1;
-
- /* Not the right baudrate, or the board's not on */
- return 0;
-}
-#endif /* not */
-
-static void
-set_rate ()
-{
- if (!SERIAL_SETBAUDRATE (desc, baudrate))
- error ("Can't set baudrate");
-}
+static struct gr_settings bug_settings = {
+ NULL, /* dcache */
+ "Bug>", /* prompt */
+ &bug_ops, /* ops */
+ bug_clear_breakpoints, /* clear_all_breakpoints */
+ bug_read_memory, /* readfunc */
+ bug_write_memory, /* writefunc */
+ gr_generic_checkin, /* checkin */
+};
+static char *cpu_check_strings[] = {
+ "=",
+ "Invalid Register",
+};
static void
-bug_open (name, from_tty)
- char *name;
+bug_open (args, from_tty)
+ char *args;
int from_tty;
{
- unsigned int prl;
- char *p;
+ if (args == NULL)
+ args = "";
- push_target (&bug_ops);
+ gr_open(args, from_tty, &bug_settings);
+ /* decide *now* whether we are on an 88100 or an 88110 */
+ sr_write_cr("rs cr06");
+ sr_expect("rs cr06");
- if (name == 0)
+ switch (gr_multi_scan(cpu_check_strings, 0))
{
- name = "";
+ case 0: /* this is an m88100 */
+ target_is_m88110 = 0;
+ break;
+ case 1: /* this is an m88110 */
+ target_is_m88110 = 1;
+ break;
+ default:
+ abort();
}
- if (is_open)
- bug_close (0);
- dev_name = strdup (name);
-
- if (!(desc = SERIAL_OPEN (dev_name)))
- perror_with_name ((char *) dev_name);
-
- SERIAL_RAW (desc);
- is_open = 1;
-
- dcache_init ();
-
- /* Hello? Are you there? */
- SERIAL_WRITE (desc, "\r", 1);
- expect_prompt ();
-
- /* Clear any break points */
- bug_clear_breakpoints ();
-
- printf_filtered ("Connected to remote 187bug system.\n");
-}
-
-/* Close out all files and local state before this target loses control. */
-
-static void
-bug_close (quitting)
- int quitting;
-{
- /* Clear any break points */
- bug_clear_breakpoints ();
-
- if (is_open)
- SERIAL_CLOSE (desc);
-
- is_open = 0;
-}
-
-/* Terminate the open connection to the remote debugger.
- Use this when you want to detach and do something else
- with your gdb. */
-void
-bug_detach (args, from_tty)
- char *args;
- int from_tty;
-{
- if (is_open)
- bug_clear_breakpoints ();
-
- pop_target (); /* calls bug_close to do the real work */
-
- if (from_tty)
- printf_filtered ("Ending remote %s debugging\n", target_shortname);
}
/* Tell the remote machine to resume. */
void
-bug_resume (step, sig)
- int step, sig;
+bug_resume (pid, step, sig)
+ int pid, step;
+ enum target_signal sig;
{
- dcache_flush ();
+ dcache_flush (gr_get_dcache());
if (step)
{
- bug_write_cr("t");
+ sr_write_cr("t");
/* Force the next bug_wait to return a trap. Not doing anything
about I/O from the target means that the user has to type
need_artificial_trap = 1;
}
else
- bug_write_cr ("g");
+ sr_write_cr ("g");
return;
}
/* Wait until the remote machine stops, then return,
storing status in STATUS just as `wait' would. */
-int
-not_bug_wait (status)
- WAITTYPE *status;
-{
- int old_timeout;
- int old_quit;
- int i;
-
- expect("Effective address: ");
- i = get_hex_word();
- expect("\r");
-
- WSETEXIT ((*status), 0);
-
- old_timeout = timeout;
- timeout = 99999; /* while user program runs. */
- old_quit = immediate_quit;
- immediate_quit = 1; /* helps ability to quit. */
-
- while (strchr("\n\r", i = readchar()) != NULL) ;;
-
- immediate_quit = old_quit;
- timeout = old_timeout;
-
- if (i == 'A')
- {
-/* At Breakpoint */
- expect("t Breakpoint");
- WSETSTOP ((*status), SIGTRAP);
-
- }
- else
- {
-/* finished cleanly */
- ;
- }
-
- expect_prompt();
-}
+static char *wait_strings[] = {
+ "At Breakpoint",
+ "Exception: Data Access Fault (Local Bus Timeout)",
+ "\r8???-Bug>",
+ "\r197-Bug>",
+ NULL,
+};
int
-bug_wait (status)
- WAITTYPE *status;
+bug_wait (pid, status)
+ int pid;
+ struct target_waitstatus *status;
{
- /* Strings to look for. '?' means match any single character.
- Note that with the algorithm we use, the initial character
- of the string cannot recur in the string, or we will not
- find some cases of the string in the input. */
-
- static char bpt[] = "At Breakpoint";
- static char exitmsg[] = "????-Bug>";
- char *bp = bpt;
- char *ep = exitmsg;
-
- /* Large enough for either sizeof (bpt) or sizeof (exitmsg) chars. */
- char swallowed[50];
-
- /* Current position in swallowed. */
- char *swallowed_p = swallowed;
-
- int ch;
- int ch_handled;
- int old_timeout = timeout;
+ int old_timeout = sr_get_timeout();
int old_immediate_quit = immediate_quit;
- int swallowed_cr = 0;
- WSETEXIT ((*status), 0);
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = 0;
- if (need_artificial_trap != 0)
+ /* read off leftovers from resume so that the rest can be passed
+ back out as stdout. */
+ if (need_artificial_trap == 0)
{
- WSETSTOP ((*status), SIGTRAP);
- need_artificial_trap--;
- /* user output from the target can be discarded here. (?) */
- expect_prompt();
- return 0;
+ sr_expect("Effective address: ");
+ (void) sr_get_hex_word();
+ sr_expect ("\r\n");
}
- /* read off leftovers from resume */
- expect("Effective address: ");
- (void) get_hex_word();
- while (strchr("\r\n", ch = readchar()) != NULL) ;;
+ sr_set_timeout(-1); /* Don't time out -- user program is running. */
+ immediate_quit = 1; /* Helps ability to QUIT */
- timeout = 99999; /* Don't time out -- user program is running. */
- immediate_quit = 1; /* Helps ability to QUIT */
- while (1)
+ switch (gr_multi_scan(wait_strings, need_artificial_trap == 0))
{
- QUIT; /* Let user quit and leave process running */
- ch_handled = 0;
- if (ch == *bp)
- {
- bp++;
- if (*bp == '\0')
- break;
- ch_handled = 1;
+ case 0: /* breakpoint case */
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ /* user output from the target can be discarded here. (?) */
+ gr_expect_prompt();
+ break;
- *swallowed_p++ = ch;
- }
- else
- {
- bp = bpt;
- }
- if (ch == *ep || *ep == '?')
- {
- ep++;
- if (*ep == '\0')
- break;
+ case 1: /* bus error */
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_BUS;
+ /* user output from the target can be discarded here. (?) */
+ gr_expect_prompt();
+ break;
- if (!ch_handled)
- *swallowed_p++ = ch;
- ch_handled = 1;
- }
- else
+ case 2: /* normal case */
+ case 3:
+ if (need_artificial_trap != 0)
{
- ep = exitmsg;
+ /* stepping */
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ need_artificial_trap--;
+ break;
}
-
- if (!ch_handled)
+ else
{
- char *p;
-
- /* Print out any characters which have been swallowed. */
- for (p = swallowed; p < swallowed_p; ++p)
- putc (*p, stdout);
- swallowed_p = swallowed;
-
- if ((ch != '\r' && ch != '\n') || swallowed_cr > 10)
- {
- putc (ch, stdout);
- swallowed_cr = 10;
- }
- swallowed_cr++;
-
+ /* exit case */
+ status->kind = TARGET_WAITKIND_EXITED;
+ status->value.integer = 0;
+ break;
}
- ch = readchar ();
- }
- if (*bp == '\0')
- {
- WSETSTOP ((*status), SIGTRAP);
- expect_prompt ();
- }
- else
- {
- WSETEXIT ((*status), 0);
+ case -1: /* trouble */
+ default:
+ fprintf_filtered (stderr,
+ "Trouble reading target during wait\n");
+ break;
}
- timeout = old_timeout;
+ sr_set_timeout(old_timeout);
immediate_quit = old_immediate_quit;
return 0;
}
"cr01", /* 32 = psr */
"fcr62", /* 33 = fpsr*/
"fcr63", /* 34 = fpcr */
- "cr04", /* 35 = sxip */
+ "ip", /* this is something of a cheat. */
+ /* 35 = sxip */
"cr05", /* 36 = snip */
"cr06", /* 37 = sfip */
+
+ "x00", "x01", "x02", "x03", "x04", "x05", "x06", "x07",
+ "x08", "x09", "x10", "x11", "x12", "x13", "x14", "x15",
+ "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
+ "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
};
return rn[regno];
}
+#if 0 /* not currently used */
+/* Read from remote while the input matches STRING. Return zero on
+ success, -1 on failure. */
+
static int
-gethex (length, start, ok)
- unsigned int length;
- char *start;
- int *ok;
+bug_scan (s)
+ char *s;
{
- int result = 0;
+ int c;
- while (length--)
+ while (*s)
{
- result <<= 4;
- if (*start >= 'a' && *start <= 'f')
- {
- result += *start - 'a' + 10;
- }
- else if (*start >= 'A' && *start <= 'F')
- {
- result += *start - 'A' + 10;
- }
- else if (*start >= '0' && *start <= '9')
+ c = sr_readchar();
+ if (c != *s++)
{
- result += *start - '0';
+ fflush(stdout);
+ printf("\nNext character is '%c' - %d and s is \"%s\".\n", c, c, --s);
+ return(-1);
}
- else
- *ok = 0;
- start++;
-
}
- return result;
-}
-static int
-timed_read (buf, n, timeout)
- char *buf;
-
-{
- int i;
- char c;
-
- i = 0;
- while (i < n)
- {
- c = readchar ();
-
- if (c == 0)
- return i;
- buf[i] = c;
- i++;
- }
- return i;
+ return(0);
}
+#endif /* never */
-bug_write (a, l)
- char *a;
+static int
+bug_srec_write_cr (s)
+ char *s;
{
- int i;
-
- SERIAL_WRITE (desc, a, l);
+ char *p = s;
- if (!quiet)
- for (i = 0; i < l; i++)
+ if (srec_echo_pace)
+ for (p = s; *p; ++p)
{
- printf ("%c", a[i]);
+ if (sr_get_debug() > 0)
+ printf ("%c", *p);
+
+ do
+ SERIAL_WRITE(sr_get_desc(), p, 1);
+ while (sr_pollchar() != *p);
}
-}
+ else
+ {
+ sr_write_cr (s);
+/* return(bug_scan (s) || bug_scan ("\n")); */
+ }
-bug_write_cr (s)
- char *s;
-{
- bug_write (s, strlen (s));
- bug_write ("\r", 1);
+ return(0);
}
/* Store register REGNO, or all if REGNO == -1. */
bug_fetch_register(regno)
int regno;
{
- REGISTER_TYPE regval;
- check_open();
+ sr_check_open();
if (regno == -1)
{
for (i = 0; i < NUM_REGS; ++i)
bug_fetch_register(i);
}
+ else if (target_is_m88110 && regno == SFIP_REGNUM)
+ {
+ /* m88110 has no sfip. */
+ long l = 0;
+ supply_register(regno, (char *) &l);
+ }
+ else if (regno < XFP_REGNUM)
+ {
+ char buffer[MAX_REGISTER_RAW_SIZE];
+
+ sr_write ("rs ", 3);
+ sr_write_cr (get_reg_name(regno));
+ sr_expect ("=");
+ store_unsigned_integer (buffer, REGISTER_RAW_SIZE (regno),
+ sr_get_hex_word());
+ gr_expect_prompt ();
+ supply_register (regno, buffer);
+ }
else
{
- bug_write("rs ", 3);
- bug_write_cr(get_reg_name(regno));
- expect("=");
- regval = get_hex_word();
- expect_prompt();
-
- /* the following registers contain flag bits in the lower to bit slots.
- Mask them off */
- if (regno == PC_REGNUM /* aka sxip */
- || regno == NPC_REGNUM /* aka snip */
- || regno == SFIP_REGNUM) /* aka sfip */
- regval &= ~0x3;
-
- supply_register(regno, (char *) ®val);
+ /* Float register so we need to parse a strange data format. */
+ long p;
+ unsigned char fpreg_buf[10];
+
+ sr_write("rs ", 3);
+ sr_write(get_reg_name(regno), strlen(get_reg_name(regno)));
+ sr_write_cr(";d");
+ sr_expect("rs");
+ sr_expect(get_reg_name(regno));
+ sr_expect(";d");
+ sr_expect("=");
+
+ /* sign */
+ p = sr_get_hex_digit(1);
+ fpreg_buf[0] = p << 7;
+
+ /* exponent */
+ sr_expect("_");
+ p = sr_get_hex_digit(1);
+ fpreg_buf[0] += (p << 4);
+ fpreg_buf[0] += sr_get_hex_digit(1);
+
+ fpreg_buf[1] = sr_get_hex_digit(1) << 4;
+
+ /* fraction */
+ sr_expect("_");
+ fpreg_buf[1] += sr_get_hex_digit(1);
+
+ fpreg_buf[2] = (sr_get_hex_digit(1) << 4) + sr_get_hex_digit(1);
+ fpreg_buf[3] = (sr_get_hex_digit(1) << 4) + sr_get_hex_digit(1);
+ fpreg_buf[4] = (sr_get_hex_digit(1) << 4) + sr_get_hex_digit(1);
+ fpreg_buf[5] = (sr_get_hex_digit(1) << 4) + sr_get_hex_digit(1);
+ fpreg_buf[6] = (sr_get_hex_digit(1) << 4) + sr_get_hex_digit(1);
+ fpreg_buf[7] = (sr_get_hex_digit(1) << 4) + sr_get_hex_digit(1);
+ fpreg_buf[8] = 0;
+ fpreg_buf[9] = 0;
+
+ gr_expect_prompt();
+ supply_register(regno, fpreg_buf);
}
return;
bug_store_register (regno)
int regno;
{
- REGISTER_TYPE regval;
char buffer[1024];
- check_open();
+ sr_check_open();
if (regno == -1)
{
{
char *regname;
- /* get_reg_name thinks that the pc is in sxip. This is only partially
- true. When *assigning* it, we must assign to ip on m88k-bug. */
-
- regname = ((regno == PC_REGNUM)
- ? "ip"
- : get_reg_name(regno));
+ regname = get_reg_name(regno);
- sprintf(buffer, "rs %s %08x",
- regname,
- read_register(regno));
+ if (target_is_m88110 && regno == SFIP_REGNUM)
+ return;
+ else if (regno < XFP_REGNUM)
+ sprintf(buffer, "rs %s %08x",
+ regname,
+ read_register(regno));
+ else
+ {
+ unsigned char *fpreg_buf =
+ (unsigned char *)®isters[REGISTER_BYTE(regno)];
+
+ sprintf(buffer, "rs %s %1x_%02x%1x_%1x%02x%02x%02x%02x%02x%02x;d",
+ regname,
+ /* sign */
+ (fpreg_buf[0] >> 7) & 0xf,
+ /* exponent */
+ fpreg_buf[0] & 0x7f,
+ (fpreg_buf[1] >> 8) & 0xf,
+ /* fraction */
+ fpreg_buf[1] & 0xf,
+ fpreg_buf[2],
+ fpreg_buf[3],
+ fpreg_buf[4],
+ fpreg_buf[5],
+ fpreg_buf[6],
+ fpreg_buf[7]);
+ }
- bug_write_cr(buffer);
- expect_prompt();
+ sr_write_cr(buffer);
+ gr_expect_prompt();
}
return;
}
-/* Get ready to modify the registers array. On machines which store
- individual registers, this doesn't need to do anything. On machines
- which store all the registers in one fell swoop, this makes sure
- that registers contains all the registers from the program being
- debugged. */
-
-void
-bug_prepare_to_store ()
-{
- /* Do nothing, since we can store individual regs */
-}
-
-static CORE_ADDR
-translate_addr (addr)
- CORE_ADDR addr;
-{
-
- return (addr);
-
-}
-
-/* Read a word from remote address ADDR and return it.
- * This goes through the data cache.
- */
int
-bug_fetch_word (addr)
- CORE_ADDR addr;
-{
- return dcache_fetch (addr);
-}
-
-/* Write a word WORD into remote address ADDR.
- This goes through the data cache. */
-
-void
-bug_store_word (addr, word)
- CORE_ADDR addr;
- int word;
-{
- dcache_poke (addr, word);
-}
-
-int
-bug_xfer_inferior_memory (memaddr, myaddr, len, write, target)
+bug_xfer_memory (memaddr, myaddr, len, write, target)
CORE_ADDR memaddr;
char *myaddr;
int len;
if (addr != memaddr || len < (int) sizeof (int))
{
/* Need part of initial word -- fetch it. */
- buffer[0] = bug_fetch_word (addr);
+ buffer[0] = gr_fetch_word (addr);
}
if (count > 1) /* FIXME, avoid if even boundary */
{
buffer[count - 1]
- = bug_fetch_word (addr + (count - 1) * sizeof (int));
+ = gr_fetch_word (addr + (count - 1) * sizeof (int));
}
/* Copy data to be written over corresponding part of buffer */
- bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
+ memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
/* Write the entire buffer. */
for (i = 0; i < count; i++, addr += sizeof (int))
{
errno = 0;
- bug_store_word (addr, buffer[i]);
+ gr_store_word (addr, buffer[i]);
if (errno)
{
for (i = 0; i < count; i++, addr += sizeof (int))
{
errno = 0;
- buffer[i] = bug_fetch_word (addr);
+ buffer[i] = gr_fetch_word (addr);
if (errno)
{
return 0;
}
/* Copy appropriate bytes out of the buffer. */
- bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
+ memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
}
return len;
}
-/* fixme: make this user settable */
-#define CHUNK_SIZE (30)
+static void
+start_load()
+{
+ char *command;
+
+ command = (srec_echo_pace ? "lo 0 ;x" : "lo 0");
-int
-bug_write_inferior_memory (memaddr, myaddr, len)
+ sr_write_cr (command);
+ sr_expect (command);
+ sr_expect ("\r\n");
+ bug_srec_write_cr ("S0030000FC");
+ return;
+}
+
+/* This is an extremely vulnerable and fragile function. I've made
+ considerable attempts to make this deterministic, but I've
+ certainly forgotten something. The trouble is that S-records are
+ only a partial file format, not a protocol. Worse, apparently the
+ m88k bug monitor does not run in real time while receiving
+ S-records. Hence, we must pay excruciating attention to when and
+ where error messages are returned, and what has actually been sent.
+
+ Each call represents a chunk of memory to be sent to the target.
+ We break that chunk into an S0 header record, some number of S3
+ data records each containing srec_bytes, and an S7 termination
+ record. */
+
+static char *srecord_strings[] = {
+ "S-RECORD",
+ "-Bug>",
+ NULL,
+};
+
+static int
+bug_write_memory (memaddr, myaddr, len)
CORE_ADDR memaddr;
unsigned char *myaddr;
int len;
{
int done;
- int todo;
int checksum;
- char buffer[(CHUNK_SIZE + 8) << 1];
+ int x;
+ int retries;
+ char *buffer = alloca ((srec_bytes + 8) << 1);
- done = 0;
+ retries = 0;
-#define LOAD_COMMAND "lo 0"
- bug_write_cr (LOAD_COMMAND);
-
- while (done < len)
+ do
{
- int thisgo;
- int idx;
- char *buf = buffer;
- CORE_ADDR address;
-
- checksum = 0;
- thisgo = len - done;
- if (thisgo > CHUNK_SIZE)
- thisgo = CHUNK_SIZE;
-
- address = memaddr + done;
- sprintf (buf, "S3%02X%08X", thisgo + 4 + 1, address);
- buf += 12;
-
- checksum += (thisgo + 4 + 1
- + (address & 0xff)
- + ((address >> 8) & 0xff)
- + ((address >> 16) & 0xff)
- + ((address >> 24) & 0xff));
-
- for (idx = 0; idx < thisgo; idx++)
+ done = 0;
+
+ if (retries > srec_max_retries)
+ return(-1);
+
+ if (retries > 0)
{
- sprintf (buf, "%02X", myaddr[idx + done]);
- checksum += myaddr[idx + done];
- buf += 2;
+ if (sr_get_debug() > 0)
+ printf("\n<retrying...>\n");
+
+ /* This gr_expect_prompt call is extremely important. Without
+ it, we will tend to resend our packet so fast that it
+ will arrive before the bug monitor is ready to receive
+ it. This would lead to a very ugly resend loop. */
+
+ gr_expect_prompt();
}
- sprintf(buf, "%02X", ~checksum & 0xff);
- bug_write_cr (buffer);
- done += thisgo;
- }
- bug_write_cr("S7060000000000F9");
- expect_prompt();
-}
+ start_load();
-void
-bug_files_info ()
-{
- char *file = "nothing";
+ while (done < len)
+ {
+ int thisgo;
+ int idx;
+ char *buf = buffer;
+ CORE_ADDR address;
+
+ checksum = 0;
+ thisgo = len - done;
+ if (thisgo > srec_bytes)
+ thisgo = srec_bytes;
+
+ address = memaddr + done;
+ sprintf (buf, "S3%02X%08X", thisgo + 4 + 1, address);
+ buf += 12;
+
+ checksum += (thisgo + 4 + 1
+ + (address & 0xff)
+ + ((address >> 8) & 0xff)
+ + ((address >> 16) & 0xff)
+ + ((address >> 24) & 0xff));
+
+ for (idx = 0; idx < thisgo; idx++)
+ {
+ sprintf (buf, "%02X", myaddr[idx + done]);
+ checksum += myaddr[idx + done];
+ buf += 2;
+ }
- if (exec_bfd)
- file = bfd_get_filename (exec_bfd);
+ if (srec_noise > 0)
+ {
+ /* FIXME-NOW: insert a deliberate error every now and then.
+ This is intended for testing/debugging the error handling
+ stuff. */
+ static int counter = 0;
+ if (++counter > srec_noise)
+ {
+ counter = 0;
+ ++checksum;
+ }
+ }
- if (exec_bfd)
-#ifdef __GO32__
- printf_filtered ("\tAttached to DOS asynctsr and running program %s\n", file);
-#else
- printf_filtered ("\tAttached to %s at %d baud and running program %s\n", dev_name, baudrate, file);
-#endif
- printf_filtered ("\ton an m88k processor.\n");
+ sprintf(buf, "%02X", ~checksum & 0xff);
+ bug_srec_write_cr (buffer);
+
+ if (srec_sleep != 0)
+ sleep(srec_sleep);
+
+ /* This pollchar is probably redundant to the gr_multi_scan
+ below. Trouble is, we can't be sure when or where an
+ error message will appear. Apparently, when running at
+ full speed from a typical sun4, error messages tend to
+ appear to arrive only *after* the s7 record. */
+
+ if ((x = sr_pollchar()) != 0)
+ {
+ if (sr_get_debug() > 0)
+ printf("\n<retrying...>\n");
+
+ ++retries;
+
+ /* flush any remaining input and verify that we are back
+ at the prompt level. */
+ gr_expect_prompt();
+ /* start all over again. */
+ start_load();
+ done = 0;
+ continue;
+ }
+
+ done += thisgo;
+ }
+
+ bug_srec_write_cr("S7060000000000F9");
+ ++retries;
+
+ /* Having finished the load, we need to figure out whether we
+ had any errors. */
+ } while (gr_multi_scan(srecord_strings, 0) == 0);;
+
+ return(0);
}
/* Copy LEN bytes of data from debugger memory at MYADDR
/* Read LEN bytes from inferior memory at MEMADDR. Put the result
at debugger address MYADDR. Returns errno value. */
-int
-bug_read_inferior_memory (memaddr, myaddr, len)
+static int
+bug_read_memory (memaddr, myaddr, len)
CORE_ADDR memaddr;
- char *myaddr;
+ unsigned char *myaddr;
int len;
{
char request[100];
unsigned int checksum;
sprintf(request, "du 0 %x:&%d", memaddr, len);
- bug_write_cr(request);
+ sr_write_cr(request);
p = buffer = alloca(len);
/* scan up through the header */
- expect("S0030000FC");
+ sr_expect("S0030000FC");
while (p < buffer + len)
{
/* scan off any white space. */
- while (readchar() != 'S') ;;
+ while (sr_readchar() != 'S') ;;
/* what kind of s-rec? */
- type = readchar();
+ type = sr_readchar();
/* scan record size */
- get_hex_byte(&size);
+ sr_get_hex_byte(&size);
checksum = size;
--size;
inaddr = 0;
goto done;
case '3':
- get_hex_byte(&c);
+ sr_get_hex_byte(&c);
inaddr = (inaddr << 8) + c;
checksum += c;
--size;
/* intentional fall through */
case '2':
- get_hex_byte(&c);
+ sr_get_hex_byte(&c);
inaddr = (inaddr << 8) + c;
checksum += c;
--size;
/* intentional fall through */
case '1':
- get_hex_byte(&c);
+ sr_get_hex_byte(&c);
inaddr = (inaddr << 8) + c;
checksum += c;
--size;
- get_hex_byte(&c);
+ sr_get_hex_byte(&c);
inaddr = (inaddr << 8) + c;
checksum += c;
--size;
for (; size; --size, ++p)
{
- get_hex_byte(p);
+ sr_get_hex_byte(p);
checksum += *p;
}
- get_hex_byte(&c);
+ sr_get_hex_byte(&c);
if (c != (~checksum & 0xff))
error("bad s-rec checksum");
}
done:
- expect_prompt();
+ gr_expect_prompt();
if (p != buffer + len)
return(1);
return(0);
}
-/* This routine is run as a hook, just before the main command loop is
- entered. If gdb is configured for the H8, but has not had its
- target specified yet, this will loop prompting the user to do so.
-*/
-
-bug_before_main_loop ()
-{
- char ttyname[100];
- char *p, *p2;
- extern FILE *instream;
-
- push_target (&bug_ops);
-}
-
#define MAX_BREAKS 16
static int num_brkpts = 0;
static int
CORE_ADDR addr;
char *save; /* Throw away, let bug save instructions */
{
- check_open ();
+ sr_check_open ();
if (num_brkpts < MAX_BREAKS)
{
num_brkpts++;
sprintf (buffer, "br %x", addr);
- bug_write_cr (buffer);
- expect_prompt ();
+ sr_write_cr (buffer);
+ gr_expect_prompt ();
return(0);
}
else
num_brkpts--;
sprintf (buffer, "nobr %x", addr);
- bug_write_cr (buffer);
- expect_prompt ();
+ sr_write_cr (buffer);
+ gr_expect_prompt ();
}
return (0);
bug_clear_breakpoints ()
{
- if (is_open)
+ if (sr_is_open())
{
- bug_write_cr ("nobr");
- expect_prompt ();
+ sr_write_cr ("nobr");
+ sr_expect("nobr");
+ gr_expect_prompt ();
}
num_brkpts = 0;
+ return(0);
}
-static void
-bug_mourn ()
-{
- bug_clear_breakpoints ();
- generic_mourn_inferior ();
-}
-
-/* Put a command string, in args, out to the bug. The bug is assumed to
- be in raw mode, all writing/reading done through desc.
- Ouput from the bug is placed on the users terminal until the
- prompt from the bug is seen.
- FIXME: Can't handle commands that take input. */
-
-void
-bug_com (args, fromtty)
- char *args;
- int fromtty;
-{
- check_open ();
-
- if (!args)
- return;
-
- /* Clear all input so only command relative output is displayed */
-
- bug_write_cr (args);
- bug_write ("\030", 1);
- expect_prompt ();
-}
-
-bug_quiet ()
-{
- quiet = !quiet;
- if (quiet)
- printf_filtered ("Snoop disabled\n");
- else
- printf_filtered ("Snoop enabled\n");
-
-}
-
-bug_device (s)
- char *s;
-{
- if (s)
- {
- dev_name = get_word (&s);
- }
-}
-
-#if 0
-static
-bug_speed (s)
- char *s;
-{
- check_open ();
-
- if (s)
- {
- char buffer[100];
- int newrate = atoi (s);
- int which = 0;
-
- if (SERIAL_SETBAUDRATE (desc, newrate))
- error ("Can't use %d baud\n", newrate);
-
- printf_filtered ("Checking target is in sync\n");
-
- printf_filtered ("Sending commands to set target to %d\n",
- baudrate);
-
- sprintf (buffer, "tm %d. N 8 1", baudrate);
- bug_write_cr (buffer);
- }
-}
-#endif /* 0 */
-static struct target_ops bug_ops =
+struct target_ops bug_ops =
{
"bug", "Remote BUG monitor",
- "Use the mvme187 board running the BUG monitor connected\n\
-by a serial line.",
+ "Use the mvme187 board running the BUG monitor connected by a serial line.",
- bug_open, bug_close,
- 0, bug_detach, bug_resume, bug_wait, /* attach */
+ bug_open, gr_close,
+ 0, gr_detach, bug_resume, bug_wait, /* attach */
bug_fetch_register, bug_store_register,
- bug_prepare_to_store,
- bug_xfer_inferior_memory,
- bug_files_info,
+ gr_prepare_to_store,
+ bug_xfer_memory,
+ gr_files_info,
bug_insert_breakpoint, bug_remove_breakpoint, /* Breakpoints */
0, 0, 0, 0, 0, /* Terminal handling */
- bug_kill, /* FIXME, kill */
+ gr_kill, /* FIXME, kill */
bug_load,
0, /* lookup_symbol */
- bug_create_inferior, /* create_inferior */
- bug_mourn, /* mourn_inferior FIXME */
+ gr_create_inferior, /* create_inferior */
+ gr_mourn, /* mourn_inferior FIXME */
0, /* can_run */
0, /* notice_signals */
process_stratum, 0, /* next */
{
add_target (&bug_ops);
- add_com ("bug <command>", class_obscure, bug_com,
- "Send a command to the BUG monitor.");
- add_com ("snoop", class_obscure, bug_quiet,
- "Show what commands are going to the monitor");
-
- add_com ("device", class_obscure, bug_device,
- "Set the terminal line for BUG communications");
+ add_show_from_set
+ (add_set_cmd ("srec-bytes", class_support, var_uinteger,
+ (char *) &srec_bytes,
+ "\
+Set the number of bytes represented in each S-record.\n\
+This affects the communication protocol with the remote target.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set
+ (add_set_cmd ("srec-max-retries", class_support, var_uinteger,
+ (char *) &srec_max_retries,
+ "\
+Set the number of retries for shipping S-records.\n\
+This affects the communication protocol with the remote target.",
+ &setlist),
+ &showlist);
#if 0
- add_com ("speed", class_obscure, bug_speed,
- "Set the terminal line speed for BUG communications");
+ /* This needs to set SREC_SIZE, not srec_frame which gets changed at the
+ end of a download. But do we need the option at all? */
+ add_show_from_set
+ (add_set_cmd ("srec-frame", class_support, var_uinteger,
+ (char *) &srec_frame,
+ "\
+Set the number of bytes in an S-record frame.\n\
+This affects the communication protocol with the remote target.",
+ &setlist),
+ &showlist);
#endif /* 0 */
- dev_name = NULL;
+ add_show_from_set
+ (add_set_cmd ("srec-noise", class_support, var_zinteger,
+ (char *) &srec_noise,
+ "\
+Set number of S-record to send before deliberately flubbing a checksum.\n\
+Zero means flub none at all. This affects the communication protocol\n\
+with the remote target.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set
+ (add_set_cmd ("srec-sleep", class_support, var_zinteger,
+ (char *) &srec_sleep,
+ "\
+Set number of seconds to sleep after an S-record for a possible error message to arrive.\n\
+This affects the communication protocol with the remote target.",
+ &setlist),
+ &showlist);
+
+ add_show_from_set
+ (add_set_cmd ("srec-echo-pace", class_support, var_boolean,
+ (char *) &srec_echo_pace,
+ "\
+Set echo-verification.\n\
+When on, use verification by echo when downloading S-records. This is\n\
+much slower, but generally more reliable.",
+ &setlist),
+ &showlist);
}