X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fremote-e7000.c;h=5e1017f4f7dc01c39ea8cb490586706fd6d1df34;hb=feb129926a8d12656f1ca4b7a8bb10268d3af4fb;hp=695180443d693962f05f29c3129ac4a6353da89b;hpb=863099f41e81cdb0797878e48d44c205576d59de;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/remote-e7000.c b/gdb/remote-e7000.c index 695180443d..5e1017f4f7 100644 --- a/gdb/remote-e7000.c +++ b/gdb/remote-e7000.c @@ -1,6 +1,8 @@ -/* Remote debugging interface for Hitachi E7000 ICE, for GDB. - Copyright 1993 Free Software Foundation, Inc. - Contributed by Cygnus Support. Written by Steve Chamberlain for Cygnus. +/* Remote debugging interface for Hitachi E7000 ICE, for GDB + Copyright 1993, 1994, 1996, 1997, 1998 Free Software Foundation, Inc. + Contributed by Cygnus Support. + + Written by Steve Chamberlain for Cygnus Support. This file is part of GDB. @@ -16,81 +18,138 @@ 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. */ + +/* The E7000 is an in-circuit emulator for the Hitachi H8/300-H and + Hitachi-SH processor. It has serial port and a lan port. + + The monitor command set makes it difficult to load large ammounts of + data over the lan without using ftp - so try not to issue load + commands when communicating over ethernet; use the ftpload command. + The monitor pauses for a second when dumping srecords to the serial + line too, so we use a slower per byte mechanism but without the + startup overhead. Even so, it's pretty slow... */ #include "defs.h" #include "gdbcore.h" +#include "gdbarch.h" +#include "inferior.h" #include "target.h" #include "wait.h" -#include +#include "value.h" +#include "command.h" #include -#include +#include "gdb_string.h" +#include "gdbcmd.h" #include #include "serial.h" +#include "remote-utils.h" +#include "symfile.h" +#include +#include -/* The E7000 is an in-circuit emulator for the Hitachi H8/300-H and -Hitachi-SH processor. It has serial port and a lan port. - -The monitor command set makes it difficult to load large ammounts of -data over the lan without using ftp - so try not to issue load -commands when communicating over ethernet; use the ftpload command. - -The monitor pauses for a second when dumping srecords to the serial -line too, so we use a slower per byte mechanism but without the -startup overhead. Even so, it's pretty slow... */ - -int using_tcp; /* nonzero if using the tcp serial driver */ +#if 1 +#define HARD_BREAKPOINTS /* Now handled by set option. */ +#define BC_BREAKPOINTS use_hard_breakpoints +#endif -extern struct target_ops e7000_ops; /* Forward declaration */ #define CTRLC 0x03 #define ENQ 0x05 #define ACK 0x06 #define CTRLZ 0x1a -char *ENQSTRING = "\005"; +extern void notice_quit PARAMS ((void)); + +extern void report_transfer_performance PARAMS ((unsigned long, + time_t, time_t)); + +extern char *sh_processor_type; + +/* Local function declarations. */ + +static void e7000_close PARAMS ((int)); + +static void e7000_fetch_register PARAMS ((int)); -int echo; -static int echo_index; -static void e7000_close (); -static void e7000_fetch_register (); -static void e7000_store_register (); +static void e7000_store_register PARAMS ((int)); -static int timeout = 5; +static void e7000_command PARAMS ((char *, int)); + +static void e7000_login_command PARAMS ((char *, int)); + +static void e7000_ftp_command PARAMS ((char *, int)); + +static void e7000_drain_command PARAMS ((char *, int)); static void expect PARAMS ((char *)); -static void expect_full_prompt PARAMS (()); -static void expect_prompt PARAMS (()); + +static void expect_full_prompt PARAMS ((void)); + +static void expect_prompt PARAMS ((void)); + +static int e7000_parse_device PARAMS ((char *args, char *dev_name, + int baudrate)); +/* Variables. */ + static serial_t e7000_desc; +/* Allow user to chose between using hardware breakpoints or memory. */ +static int use_hard_breakpoints = 0; /* use sw breakpoints by default */ + +/* Nonzero if using the tcp serial driver. */ + +static int using_tcp; /* direct tcp connection to target */ +static int using_tcp_remote; /* indirect connection to target + via tcp to controller */ + +/* Nonzero if using the pc isa card. */ + +static int using_pc; + +extern struct target_ops e7000_ops; /* Forward declaration */ + +char *ENQSTRING = "\005"; + +/* Nonzero if some routine (as opposed to the user) wants echoing. + FIXME: Do this reentrantly with an extra parameter. */ -/* Send data to e7000debug. Works just like printf. */ +static int echo; + +static int ctrl_c; + +static int timeout = 20; + +/* Send data to e7000debug. */ static void -printf_e7000debug (va_alist) - va_dcl +puts_e7000debug (buf) + char *buf; { - va_list args; - char *pattern; - char buf[200]; - - va_start (args); + if (!e7000_desc) + error ("Use \"target e7000 ...\" first."); - pattern = va_arg (args, char *); + if (remote_debug) + printf_unfiltered ("Sending %s\n", buf); - vsprintf (buf, pattern, args); if (SERIAL_WRITE (e7000_desc, buf, strlen (buf))) - fprintf (stderr, "SERIAL_WRITE failed: %s\n", safe_strerror (errno)); + fprintf_unfiltered (gdb_stderr, "SERIAL_WRITE failed: %s\n", safe_strerror (errno)); - /* And expect to see it echoed */ - expect (buf); + /* And expect to see it echoed, unless using the pc interface */ +#if 0 + if (!using_pc) +#endif + expect (buf); } static void putchar_e7000 (x) + int x; { char b[1]; + b[0] = x; SERIAL_WRITE (e7000_desc, b, 1); } @@ -102,65 +161,130 @@ write_e7000 (s) SERIAL_WRITE (e7000_desc, s, strlen (s)); } +static int +normal (x) + int x; +{ + if (x == '\n') + return '\r'; + return x; +} + /* Read a character from the remote system, doing all the fancy timeout - stuff. */ + stuff. Handles serial errors and EOF. If TIMEOUT == 0, and no chars, + returns -1, else returns next char. Discards chars > 127. */ static int readchar (timeout) int timeout; { int c; + do { c = SERIAL_READCHAR (e7000_desc, timeout); } while (c > 127); + if (c == SERIAL_TIMEOUT) { if (timeout == 0) - return c; /* Polls shouldn't generate timeout errors */ - + return -1; + echo = 0; error ("Timeout reading from remote system."); } - return c; + else if (c < 0) + error ("Serial communication error"); + + if (remote_debug) + { + putchar_unfiltered (c); + gdb_flush (gdb_stdout); + } + + return normal (c); +} + +#if 0 +char * +tl (x) +{ + static char b[8][10]; + static int p; + + p++; + p &= 7; + if (x >= ' ') + { + b[p][0] = x; + b[p][1] = 0; + } + else + { + sprintf (b[p], "<%d>", x); + } + + return b[p]; } +#endif + +/* Scan input from the remote system, until STRING is found. If + DISCARD is non-zero, then discard non-matching input, else print it + out. Let the user break out immediately. */ -/* Scan input from the remote system, until STRING is found. If DISCARD is - non-zero, then discard non-matching input, else print it out. - Let the user break out immediately. */ static void expect (string) char *string; { char *p = string; int c; + int nl = 0; - immediate_quit = 1; while (1) - { c = readchar (timeout); - if (c == SERIAL_ERROR) +#if 0 + notice_quit (); + if (quit_flag == 1) { - error ("Serial communication error"); + if (ctrl_c) + { + putchar_e7000 (CTRLC); + --ctrl_c; + } + else + { + quit (); + } } - if (echo_index) +#endif + + if (echo) { - if (c != '\r') - putchar (c); - fflush (stdout); + if (c == '\r' || c == '\n') + { + if (!nl) + putchar_unfiltered ('\n'); + nl = 1; + } + else + { + nl = 0; + putchar_unfiltered (c); + } + gdb_flush (gdb_stdout); } - if (c == *p++) + if (normal (c) == normal (*p++)) { if (*p == '\0') - { - immediate_quit = 0; - return; - } + return; } else { p = string; + + if (normal (c) == normal (string[0])) + p++; } } } @@ -171,37 +295,29 @@ expect (string) o give your command o *then* wait for the prompt. - Thus the last thing that a procedure does with the serial line - will be an expect_prompt(). Exception: e7000_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 e7000_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. */ + Thus the last thing that a procedure does with the serial line will + be an expect_prompt(). Exception: e7000_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 + e7000_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 () { -#if defined (LOG_FILE) - /* This is a convenient place to do this. The idea is to do it often - enough that we never lose much data if we terminate abnormally. */ - fflush (log_file); -#endif expect (":"); } + static void expect_full_prompt () { -#if defined (LOG_FILE) - /* This is a convenient place to do this. The idea is to do it often - enough that we never lose much data if we terminate abnormally. */ - fflush (log_file); -#endif - expect ("\n:"); + expect ("\r:"); } static int -get_hex_digit (ch) +convert_hex_digit (ch) + int ch; { if (ch >= '0' && ch <= '9') return ch - '0'; @@ -210,20 +326,17 @@ get_hex_digit (ch) else if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; return -1; - } - - static int get_hex (start) int *start; { - int value = get_hex_digit (*start); + int value = convert_hex_digit (*start); int try; *start = readchar (timeout); - while ((try = get_hex_digit (*start)) >= 0) + while ((try = convert_hex_digit (*start)) >= 0) { value <<= 4; value += try; @@ -232,8 +345,9 @@ get_hex (start) return value; } -/* Get N 32-bit words from remote, each preceded by a space, - and put them in registers starting at REGNO. */ +#if 0 +/* Get N 32-bit words from remote, each preceded by a space, and put + them in registers starting at REGNO. */ static void get_hex_regs (n, regno) @@ -253,9 +367,11 @@ get_hex_regs (n, regno) supply_register (regno++, (char *) &val); } } +#endif /* This is called not only when we first attach, but also when the user types "run" after having attached. */ + static void e7000_create_inferior (execfile, args, env) char *execfile; @@ -268,7 +384,7 @@ e7000_create_inferior (execfile, args, env) error ("Can't pass arguments to remote E7000DEBUG process"); if (execfile == 0 || exec_bfd == 0) - error ("No exec file specified"); + error ("No executable file specified"); entry_pt = (int) bfd_get_start_address (exec_bfd); @@ -295,8 +411,8 @@ e7000_create_inferior (execfile, args, env) proceed ((CORE_ADDR) entry_pt, -1, 0); /* Let 'er rip... */ } -/* Open a connection to a remote debugger. - NAME is the filename used for communication. */ +/* Open a connection to a remote debugger. NAME is the filename used + for communication. */ static int baudrate = 9600; static char dev_name[100]; @@ -307,6 +423,7 @@ static char *passwd = ""; static char *dir = ""; /* Grab the next token and buy some space for it */ + static char * next (ptr) char **ptr; @@ -315,10 +432,9 @@ next (ptr) char *s; char *r; int l = 0; + while (*p && *p == ' ') - { - p++; - } + p++; s = p; while (*p && (*p != ' ' && *p != '\t')) { @@ -332,8 +448,8 @@ next (ptr) return r; } -static -e7000_login (args, from_tty) +static void +e7000_login_command (args, from_tty) char *args; int from_tty; { @@ -345,7 +461,7 @@ e7000_login (args, from_tty) dir = next (&args); if (from_tty) { - printf ("Set info to %s %s %s %s\n", machine, user, passwd, dir); + printf_unfiltered ("Set info to %s %s %s %s\n", machine, user, passwd, dir); } } else @@ -356,104 +472,217 @@ e7000_login (args, from_tty) /* Start an ftp transfer from the E7000 to a host */ -static -e7000_ftp (args, from_tty) +static void +e7000_ftp_command (args, from_tty) char *args; int from_tty; { + /* FIXME: arbitrary limit on machine names and such. */ + char buf[200]; + int oldtimeout = timeout; - timeout = 10; - echo_index++; - printf_e7000debug ("ftp %s\r", machine); + timeout = remote_timeout; + + sprintf (buf, "ftp %s\r", machine); + puts_e7000debug (buf); expect (" Username : "); - printf_e7000debug ("%s\r", user); + sprintf (buf, "%s\r", user); + puts_e7000debug (buf); expect (" Password : "); write_e7000 (passwd); write_e7000 ("\r"); expect ("success\r"); expect ("FTP>"); - printf_e7000debug ("cd %s\r", dir); + sprintf (buf, "cd %s\r", dir); + puts_e7000debug (buf); expect ("FTP>"); - printf_e7000debug ("ll 0;s:%s\r", args); + sprintf (buf, "ll 0;s:%s\r", args); + puts_e7000debug (buf); expect ("FTP>"); - printf_e7000debug ("bye\r"); + puts_e7000debug ("bye\r"); expect (":"); - echo_index--; timeout = oldtimeout; } -static void -e7000_open (args, from_tty) +static int +e7000_parse_device (args, dev_name, baudrate) char *args; - int from_tty; + char *dev_name; + int baudrate; { - int n; - char junk[100]; - int sync; - target_preopen (from_tty); - - if (args) - n = sscanf (args, " %s %d %s", dev_name, &baudrate, junk); - else - n = 0; - if (n != 1 && n != 2) - error ("Bad arguments. Usage:\ttarget e7000 \n\ -or \t\ttarget e7000 [:]\n"); - - if (n == 1 && strchr (dev_name, ':') == 0) + char junk[128]; + int n = 0; + if (args && strcasecmp (args, "pc") == 0) { - /* Default to normal telnet port */ - strcat (dev_name, ":23"); + strcpy (dev_name, args); + using_pc = 1; } + else + { + /* FIXME! temp hack to allow use with port master - + target tcp_remote */ + if (args && strncmp (args, "tcp", 10) == 0) + { + char com_type[128]; + n = sscanf (args, " %s %s %d %s", com_type, dev_name, &baudrate, junk); + using_tcp_remote = 1; + n--; + } + else if (args) + { + n = sscanf (args, " %s %d %s", dev_name, &baudrate, junk); + } - push_target (&e7000_ops); - e7000_desc = SERIAL_OPEN (dev_name); + if (n != 1 && n != 2) + { + error ("Bad arguments. Usage:\ttarget e7000 \n\ +or \t\ttarget e7000 [:]\n\ +or \t\ttarget e7000 tcp_remote [:]\n\ +or \t\ttarget e7000 pc\n"); + } + +#if !defined(__GO32__) && !defined(_WIN32) + /* FIXME! test for ':' is ambiguous */ + if (n == 1 && strchr (dev_name, ':') == 0) + { + /* Default to normal telnet port */ + /* serial_open will use this to determine tcp communication */ + strcat (dev_name, ":23"); + } +#endif + if (!using_tcp_remote && strchr (dev_name, ':')) + using_tcp = 1; + } + return n; +} - if (!e7000_desc) - perror_with_name (dev_name); +/* Stub for catch_errors. */ - using_tcp = strcmp (e7000_desc->ops->name, "tcp") == 0; +static int +e7000_start_remote (dummy) + char *dummy; +{ + int loop; + int sync; + int try; + int quit_trying; - SERIAL_SETBAUDRATE (e7000_desc, baudrate); - SERIAL_RAW (e7000_desc); + immediate_quit = 1; /* Allow user to interrupt it */ /* Hello? Are you there? */ sync = 0; - while (!sync) + loop = 0; + try = 0; + quit_trying = 20; + putchar_e7000 (CTRLC); + while (!sync && ++try <= quit_trying) { int c; - if (from_tty) - printf_unfiltered ("[waiting for e7000...]\n"); - write_e7000 ("\r\n"); - c = SERIAL_READCHAR (e7000_desc, 3); - while (c != SERIAL_TIMEOUT) + + printf_unfiltered ("[waiting for e7000...]\n"); + + write_e7000 ("\r"); + c = readchar (1); + + /* FIXME! this didn't seem right-> while (c != SERIAL_TIMEOUT) + * we get stuck in this loop ... + * We may never timeout, and never sync up :-( + */ + while (!sync && c != -1) { /* Dont echo cr's */ - if (from_tty && c != '\r') + if (c != '\r') { - putchar (c); - fflush (stdout); + putchar_unfiltered (c); + gdb_flush (gdb_stdout); } + /* Shouldn't we either break here, or check for sync in inner loop? */ if (c == ':') + sync = 1; + + if (loop++ == 20) { - sync = 1; + putchar_e7000 (CTRLC); + loop = 0; } - c = SERIAL_READCHAR (e7000_desc, 3); + + QUIT; + if (quit_flag) { putchar_e7000 (CTRLC); - quit_flag = 0; + /* Was-> quit_flag = 0; */ + c = -1; + quit_trying = try + 1; /* we don't want to try anymore */ + } + else + { + c = readchar (1); } } } - printf_e7000debug ("\r\n"); + + if (!sync) + { + fprintf_unfiltered (gdb_stderr, "Giving up after %d tries...\n", try); + error ("Unable to syncronize with target.\n"); + } + + puts_e7000debug ("\r"); + expect_prompt (); + puts_e7000debug ("b -\r"); /* Clear breakpoints */ expect_prompt (); - if (from_tty) - printf_filtered ("Remote %s connected to %s\n", target_shortname, - dev_name); + immediate_quit = 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. */ + + 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); + + return 1; +} + +static void +e7000_open (args, from_tty) + char *args; + int from_tty; +{ + int n; + + target_preopen (from_tty); + + n = e7000_parse_device (args, dev_name, baudrate); + + push_target (&e7000_ops); + e7000_desc = SERIAL_OPEN (dev_name); + + if (!e7000_desc) + perror_with_name (dev_name); + + SERIAL_SETBAUDRATE (e7000_desc, baudrate); + SERIAL_RAW (e7000_desc); + +#ifdef GDB_TARGET_IS_H8300 + h8300hmode = 1; +#endif + + /* Start the remote connection; if error (0), discard this target. + In particular, if the user quits, be sure to discard it + (we'd be in an inconsistent state otherwise). */ + if (!catch_errors (e7000_start_remote, (char *) 0, + "Couldn't establish connection to remote target\n", RETURN_MASK_ALL)) + if (from_tty) + printf_filtered ("Remote target %s connected to %s\n", target_shortname, + dev_name); } /* Close out all files and local state before this target loses control. */ @@ -469,16 +698,16 @@ e7000_close (quitting) } } -/* Terminate the open connection to the remote debugger. - Use this when you want to detach and do something else - with your gdb. */ +/* Terminate the open connection to the remote debugger. Use this + when you want to detach and do something else with your gdb. */ + static void e7000_detach (from_tty) int from_tty; { pop_target (); /* calls e7000_close to do the real work */ if (from_tty) - printf ("Ending remote %s debugging\n", target_shortname); + printf_unfiltered ("Ending remote %s debugging\n", target_shortname); } /* Tell the remote machine to resume. */ @@ -488,36 +717,51 @@ e7000_resume (pid, step, sig) int pid, step, sig; { if (step) - { - printf_e7000debug ("S\r"); - } + puts_e7000debug ("S\r"); else - { - printf_e7000debug ("G\r"); - } + puts_e7000debug ("G\r"); } /* Read the remote registers into the block REGS. - A reg dump looks like: + For the H8/300 a register dump looks like: + PC=00021A CCR=80:I******* + ER0 - ER3 0000000A 0000002E 0000002E 00000000 + ER4 - ER7 00000000 00000000 00000000 00FFEFF6 + 000218 MOV.B R1L,R2L + STEP NORMAL END or + BREAK POINT */ #ifdef GDB_TARGET_IS_H8300 -char *want = "\n\ - PC=%p CCR=%c\n\ + +char *want_h8300h = "PC=%p CCR=%c\n\ + ER0 - ER3 %0 %1 %2 %3\n\ + ER4 - ER7 %4 %5 %6 %7\n"; + +char *want_nopc_h8300h = "%p CCR=%c\n\ + ER0 - ER3 %0 %1 %2 %3\n\ + ER4 - ER7 %4 %5 %6 %7"; + +char *want_h8300s = "PC=%p CCR=%c\n\ + MACH=\n\ + ER0 - ER3 %0 %1 %2 %3\n\ + ER4 - ER7 %4 %5 %6 %7\n"; + +char *want_nopc_h8300s = "%p CCR=%c EXR=%9\n\ ER0 - ER3 %0 %1 %2 %3\n\ - ER4 - ER7 %4 %5 %6 %7\n\ -:"; + ER4 - ER7 %4 %5 %6 %7"; #endif + #ifdef GDB_TARGET_IS_SH -char *want = "\n\PC=%16 SR=%22\n\ - PR=%17 GBR=%18 VBR=%19\n\ - MACH=%20 MACL=%21\n\ - R0-7 %0 %1 %2 %3 %4 %5 %6 %7\n\ - R8-15 %8 %9 %10 %11 %12 %13 %14 %15\n\ -:"; + +char *want = "PC=%16 SR=%22\n\ +PR=%17 GBR=%18 VBR=%19\n\ +MACH=%20 MACL=%21\n\ +R0-7 %0 %1 %2 %3 %4 %5 %6 %7\n\ +R8-15 %8 %9 %10 %11 %12 %13 %14 %15\n"; char *want_nopc = "%16 SR=%22\n\ PR=%17 GBR=%18 VBR=%19\n\ @@ -525,79 +769,93 @@ char *want_nopc = "%16 SR=%22\n\ R0-7 %0 %1 %2 %3 %4 %5 %6 %7\n\ R8-15 %8 %9 %10 %11 %12 %13 %14 %15"; +char *want_sh3 = "PC=%16 SR=%22\n\ +PR=%17 GBR=%18 VBR=%19\n\ +MACH=%20 MACL=%21 SSR=%23 SPC=%24\n\ +R0-7 %0 %1 %2 %3 %4 %5 %6 %7\n\ +R8-15 %8 %9 %10 %11 %12 %13 %14 %15\n\ +R0_BANK0-R3_BANK0 %25 %26 %27 %28\n\ +R4_BANK0-R7_BANK0 %29 %30 %31 %32\n\ +R0_BANK1-R3_BANK1 %33 %34 %35 %36\n\ +R4_BANK1-R7_BANK1 %37 %38 %39 %40"; + +char *want_sh3_nopc = "%16 SR=%22\n\ + PR=%17 GBR=%18 VBR=%19\n\ + MACH=%20 MACL=%21 SSR=%22 SPC=%23\n\ + R0-7 %0 %1 %2 %3 %4 %5 %6 %7\n\ + R8-15 %8 %9 %10 %11 %12 %13 %14 %15\n\ + R0_BANK0-R3_BANK0 %25 %26 %27 %28\n\ + R4_BANK0-R7_BANK0 %29 %30 %31 %32\n\ + R0_BANK1-R3_BANK1 %33 %34 %35 %36\n\ + R4_BANK1-R7_BANK1 %37 %38 %39 %40"; #endif -static -int +static int gch () { - int c = readchar (timeout); - if (echo) - { - if (c >= ' ') - printf ("%c", c); - else if (c == '\n') - printf ("\n", c); - } - return c; + return readchar (timeout); } - -static -unsigned int +static unsigned int gbyte () { - int high = get_hex_digit (gch ()); - int low = get_hex_digit (gch ()); + int high = convert_hex_digit (gch ()); + int low = convert_hex_digit (gch ()); + return (high << 4) + low; } void fetch_regs_from_dump (nextchar, want) - int (*nextchar)(); + int (*nextchar) (); char *want; { int regno; char buf[MAX_REGISTER_RAW_SIZE]; - int thischar = nextchar(); - + int thischar = nextchar (); + while (*want) { switch (*want) { case '\n': - while (thischar != '\n') - thischar = nextchar(); - thischar = nextchar(); - while (thischar == '\r') - thischar = nextchar(); + /* Skip to end of line and then eat all new line type stuff */ + while (thischar != '\n' && thischar != '\r') + thischar = nextchar (); + while (thischar == '\n' || thischar == '\r') + thischar = nextchar (); want++; break; case ' ': - while (thischar == ' ' || thischar == '\t') - thischar = nextchar(); + while (thischar == ' ' + || thischar == '\t' + || thischar == '\r' + || thischar == '\n') + thischar = nextchar (); want++; break; - + default: if (*want == thischar) { want++; if (*want) - thischar = nextchar(); - + thischar = nextchar (); + } - else if (thischar == ' ') + else if (thischar == ' ' || thischar == '\n' || thischar == '\r') { - thischar = nextchar(); + thischar = nextchar (); } - else { - error("out of sync in fetch registers"); - } - + else + { + error ("out of sync in fetch registers wanted <%s>, got <%c 0x%x>", + want, thischar, thischar); + } + break; case '%': /* Got a register command */ @@ -629,28 +887,27 @@ fetch_regs_from_dump (nextchar, want) break; #endif - default: - if (isdigit(want[0])) + if (isdigit (want[0])) { - if (isdigit(want[1])) + if (isdigit (want[1])) { regno = (want[0] - '0') * 10 + want[1] - '0'; - want+=2; + want += 2; } - else + else { regno = want[0] - '0'; want++; } } - + else - abort(); + abort (); } store_signed_integer (buf, - REGISTER_RAW_SIZE(regno), - (LONGEST)get_hex(&thischar, nextchar)); + REGISTER_RAW_SIZE (regno), + (LONGEST) get_hex (&thischar, nextchar)); supply_register (regno, buf); break; } @@ -661,23 +918,41 @@ static void e7000_fetch_registers () { int regno; + char *wanted; - printf_e7000debug ("R\r"); - fetch_regs_from_dump (gch, want); + puts_e7000debug ("R\r"); + +#ifdef GDB_TARGET_IS_SH + wanted = want; + if (TARGET_ARCHITECTURE->arch == bfd_arch_sh) + switch (TARGET_ARCHITECTURE->mach) + { + case bfd_mach_sh3: + case bfd_mach_sh3e: + case bfd_mach_sh4: + wanted = want_sh3; + } +#else + if (h8300smode) + wanted = want_h8300s; + else + wanted = want_h8300h; +#endif + fetch_regs_from_dump (gch, wanted); /* And supply the extra ones the simulator uses */ for (regno = NUM_REALREGS; regno < NUM_REGS; regno++) { int buf = 0; + supply_register (regno, (char *) (&buf)); } } -/* Fetch register REGNO, or all registers if REGNO is -1. - Returns errno value. */ +/* Fetch register REGNO, or all registers if REGNO is -1. Returns + errno value. */ -static -void +static void e7000_fetch_register (regno) int regno; { @@ -697,80 +972,84 @@ e7000_store_registers () registers_changed (); } -/* Store register REGNO, or all if REGNO == 0. - Return errno value. */ +/* Store register REGNO, or all if REGNO == 0. Return errno value. */ + static void e7000_store_register (regno) int regno; { + char buf[200]; + if (regno == -1) { e7000_store_registers (); return; } + #ifdef GDB_TARGET_IS_H8300 if (regno <= 7) { - printf_e7000debug (".ER%d %x\r", regno, - read_register (regno)); - + sprintf (buf, ".ER%d %x\r", regno, read_register (regno)); + puts_e7000debug (buf); } else if (regno == PC_REGNUM) { - printf_e7000debug (".PC %x\r", - read_register (regno)); + sprintf (buf, ".PC %x\r", read_register (regno)); + puts_e7000debug (buf); } else if (regno == CCR_REGNUM) { - printf_e7000debug (".CCR %x\r", - read_register (regno)); + sprintf (buf, ".CCR %x\r", read_register (regno)); + puts_e7000debug (buf); } -#endif +#endif /* GDB_TARGET_IS_H8300 */ #ifdef GDB_TARGET_IS_SH switch (regno) { default: - printf_e7000debug (".R%d %x\r", regno, - read_register (regno)); - + sprintf (buf, ".R%d %x\r", regno, read_register (regno)); + puts_e7000debug (buf); break; + case PC_REGNUM: - printf_e7000debug (".PC %x\r", - read_register (regno)); + sprintf (buf, ".PC %x\r", read_register (regno)); + puts_e7000debug (buf); break; + case SR_REGNUM: - printf_e7000debug (".SR %x\r", - read_register (regno)); + sprintf (buf, ".SR %x\r", read_register (regno)); + puts_e7000debug (buf); break; case PR_REGNUM: - printf_e7000debug (".PR %x\r", - read_register (regno)); + sprintf (buf, ".PR %x\r", read_register (regno)); + puts_e7000debug (buf); break; case GBR_REGNUM: - printf_e7000debug (".GBR %x\r", - read_register (regno)); + sprintf (buf, ".GBR %x\r", read_register (regno)); + puts_e7000debug (buf); break; case VBR_REGNUM: - printf_e7000debug (".VBR %x\r", - read_register (regno)); + sprintf (buf, ".VBR %x\r", read_register (regno)); + puts_e7000debug (buf); break; case MACH_REGNUM: - printf_e7000debug (".MACH %x\r", - read_register (regno)); + sprintf (buf, ".MACH %x\r", read_register (regno)); + puts_e7000debug (buf); break; case MACL_REGNUM: - printf_e7000debug (".MACL %x\r", - read_register (regno)); + sprintf (buf, ".MACL %x\r", read_register (regno)); + puts_e7000debug (buf); break; } -#endif +#endif /* GDB_TARGET_IS_SH */ + expect_prompt (); } @@ -789,23 +1068,24 @@ e7000_prepare_to_store () static void e7000_files_info () { - printf ("\tAttached to %s at %d baud.\n", - dev_name, baudrate); + printf_unfiltered ("\tAttached to %s at %d baud.\n", dev_name, baudrate); } -static -int +static int stickbyte (where, what) char *where; unsigned int what; { static CONST char digs[] = "0123456789ABCDEF"; + where[0] = digs[(what >> 4) & 0xf]; where[1] = digs[(what & 0xf) & 0xf]; + return what; } -/* Write a small ammount of memory */ +/* Write a small ammount of memory. */ + static int write_small (memaddr, myaddr, len) CORE_ADDR memaddr; @@ -813,40 +1093,44 @@ write_small (memaddr, myaddr, len) int len; { int i; + char buf[200]; + for (i = 0; i < len; i++) { - if (((memaddr + i) & 3) == 0 - && (i + 3 < len)) + if (((memaddr + i) & 3) == 0 && (i + 3 < len)) { /* Can be done with a long word */ - printf_e7000debug ("m %x %x%02x%02x%02x;l\r", - memaddr + i, - myaddr[i], - myaddr[i + 1], - myaddr[i + 2], - myaddr[i + 3]); + sprintf (buf, "m %x %x%02x%02x%02x;l\r", + memaddr + i, + myaddr[i], myaddr[i + 1], myaddr[i + 2], myaddr[i + 3]); + puts_e7000debug (buf); i += 3; } else { - printf_e7000debug ("m %x %x\r", memaddr + i, myaddr[i]); + sprintf (buf, "m %x %x\r", memaddr + i, myaddr[i]); + puts_e7000debug (buf); } } + expect_prompt (); + return len; } -/* Write a large ammount of memory, this only works with the serial mode enabled. - Command is sent as - il ;s:s\r -> - <- il ;s:s\r - <- ENQ - ACK -> - <- LO s\r - Srecords... - ^Z -> - <- ENQ - ACK -> - <- : + +/* Write a large ammount of memory, this only works with the serial + mode enabled. Command is sent as + + il ;s:s\r -> + <- il ;s:s\r + <- ENQ + ACK -> + <- LO s\r + Srecords... + ^Z -> + <- ENQ + ACK -> + <- : */ static int @@ -859,10 +1143,10 @@ write_large (memaddr, myaddr, len) #define maxstride 128 int stride; - printf_e7000debug ("il ;s:s\r"); + puts_e7000debug ("IL ;S:FK\r"); expect (ENQSTRING); putchar_e7000 (ACK); - expect ("LO s\r"); + expect ("LO FK\r"); for (i = 0; i < len; i += stride) { @@ -872,6 +1156,7 @@ write_large (memaddr, myaddr, len) int check_sum; int where = 0; int alen; + stride = len - i; if (stride > maxstride) stride = maxstride; @@ -879,17 +1164,15 @@ write_large (memaddr, myaddr, len) compose[where++] = 'S'; check_sum = 0; if (address >= 0xffffff) - { - alen = 4; - } + alen = 4; else if (address >= 0xffff) - { - alen = 3; - } + alen = 3; else alen = 2; - compose[where++] = alen - 1 + '0'; /* insert type */ - check_sum += stickbyte (compose + where, alen + stride + 1); /* Insert length */ + /* Insert type. */ + compose[where++] = alen - 1 + '0'; + /* Insert length. */ + check_sum += stickbyte (compose + where, alen + stride + 1); where += 2; while (alen > 0) { @@ -903,14 +1186,15 @@ write_large (memaddr, myaddr, len) check_sum += stickbyte (compose + where, myaddr[i + j]); where += 2; } - stickbyte (compose + where, ~check_sum); - where += 2; compose[where++] = '\r'; + compose[where++] = '\n'; + compose[where++] = 0; + SERIAL_WRITE (e7000_desc, compose, where); - j = SERIAL_READCHAR (e7000_desc, 0); - if (j == SERIAL_TIMEOUT) + j = readchar (0); + if (j == -1) { /* This is ok - nothing there */ } @@ -922,58 +1206,49 @@ write_large (memaddr, myaddr, len) } else { - printf ("Whats this %d\n", j); + printf_unfiltered ("@%d}@", j); + while ((j = readchar (0)) > 0) + { + printf_unfiltered ("@{%d}@", j); + } } - } + /* Send the trailer record */ write_e7000 ("S70500000000FA\r"); putchar_e7000 (CTRLZ); expect (ENQSTRING); putchar_e7000 (ACK); expect (":"); + return len; } -/* Copy LEN bytes of data from debugger memory at MYADDR - to inferior's memory at MEMADDR. Returns length moved. +/* Copy LEN bytes of data from debugger memory at MYADDR to inferior's + memory at MEMADDR. Returns length moved. + + Can't use the Srecord load over ethernet, so don't use fast method + then. */ - Can't use the Srecord load over ethernet, so dont use - fast method then. - */ static int e7000_write_inferior_memory (memaddr, myaddr, len) CORE_ADDR memaddr; unsigned char *myaddr; int len; { - if (len < 16 || using_tcp) - { - return write_small (memaddr, myaddr, len); - } + if (len < 16 || using_tcp || using_pc) + return write_small (memaddr, myaddr, len); else - { - return write_large (memaddr, myaddr, len); - } + return write_large (memaddr, myaddr, len); } /* Read LEN bytes from inferior memory at MEMADDR. Put the result at debugger address MYADDR. Returns length moved. - Done by requesting an srecord dump from the E7000. - */ - - - -/* Read LEN bytes from inferior memory at MEMADDR. Put the result - at debugger address MYADDR. Returns length moved. - - - Small transactions we send - m ;l - and receive - 00000000 12345678 ? - + Small transactions we send + m ;l + and receive + 00000000 12345678 ? */ static int @@ -985,81 +1260,88 @@ e7000_read_inferior_memory (memaddr, myaddr, len) int count; int c; int i; + char buf[200]; /* Starting address of this pass. */ +/* printf("READ INF %x %x %d\n", memaddr, myaddr, len); */ if (((memaddr - 1) + len) < memaddr) { errno = EIO; return 0; } - printf_e7000debug ("m %x;l\r", memaddr); + sprintf (buf, "m %x;l\r", memaddr); + puts_e7000debug (buf); - for (count = 0; count < len; count += 4) + for (count = 0; count < len; count += 4) { /* Suck away the address */ - c = gch(); + c = gch (); while (c != ' ') - c = gch(); - c = gch(); - if (c == '*') + c = gch (); + c = gch (); + if (c == '*') { /* Some kind of error */ - expect_prompt(); + puts_e7000debug (".\r"); /* Some errors leave us in memory input mode */ + expect_full_prompt (); return -1; } while (c != ' ') - c = gch(); + c = gch (); /* Now read in the data */ - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { - int b = gbyte(); - if (count + i < len) { - myaddr[count + i] = b; - } + int b = gbyte (); + if (count + i < len) + { + myaddr[count + i] = b; + } } /* Skip the trailing ? and send a . to end and a cr for more */ - gch(); - gch(); + gch (); + gch (); if (count + 4 >= len) - printf_e7000debug(".\r"); + puts_e7000debug (".\r"); else - printf_e7000debug("\r"); + puts_e7000debug ("\r"); + } - expect_prompt(); + expect_prompt (); + return len; } -#if 0 -/* - For large transfers we used to send +/* + For large transfers we used to send - d \r - and receive - < D A T A > < ASCII CODE > - 000000 5F FD FD FF DF 7F DF FF 01 00 01 00 02 00 08 04 "_..............." - 000010 FF D7 FF 7F D7 F1 7F FF 00 05 00 00 08 00 40 00 "..............@." - 000020 7F FD FF F7 7F FF FF F7 00 00 00 00 00 00 00 00 "................" + d \r - A cost in chars for each transaction of 80 + 5*n-bytes. + and receive +
< D A T A > < ASCII CODE > + 00000000 5F FD FD FF DF 7F DF FF 01 00 01 00 02 00 08 04 "_..............." + 00000010 FF D7 FF 7F D7 F1 7F FF 00 05 00 00 08 00 40 00 "..............@." + 00000020 7F FD FF F7 7F FF FF F7 00 00 00 00 00 00 00 00 "................" + A cost in chars for each transaction of 80 + 5*n-bytes. - Large transactions could be done with the srecord load code, but - there is a pause for a second before dumping starts, which slows the - average rate down! -*/ + Large transactions could be done with the srecord load code, but + there is a pause for a second before dumping starts, which slows the + average rate down! + */ static int -e7000_read_inferior_memory (memaddr, myaddr, len) +e7000_read_inferior_memory_large (memaddr, myaddr, len) CORE_ADDR memaddr; unsigned char *myaddr; int len; { int count; int c; + char buf[200]; /* Starting address of this pass. */ @@ -1069,33 +1351,27 @@ e7000_read_inferior_memory (memaddr, myaddr, len) return 0; } - printf_e7000debug ("d %x %x\r", memaddr, memaddr + len - 1); + sprintf (buf, "d %x %x\r", memaddr, memaddr + len - 1); + puts_e7000debug (buf); count = 0; c = gch (); - /* First skip the command */ - while (c == '\n') + /* skip down to the first ">" */ + while (c != '>') c = gch (); - - while (c == ' ') - c = gch (); - if (c == '*') - { - expect ("\r"); - return -1; - } - - /* Skip the title line */ - while (c != '\n') + /* now skip to the end of that line */ + while (c != '\r') c = gch (); c = gch (); + while (count < len) { - /* Skip the address */ + /* get rid of any white space before the address */ while (c <= ' ') c = gch (); + /* Skip the address */ get_hex (&c); /* read in the bytes on the line */ @@ -1108,17 +1384,20 @@ e7000_read_inferior_memory (memaddr, myaddr, len) myaddr[count++] = get_hex (&c); } } - - while (c != '\n') + /* throw out the rest of the line */ + while (c != '\r') c = gch (); } + /* wait for the ":" prompt */ while (c != ':') c = gch (); return len; } +#if 0 + static int fast_but_for_the_pause_e7000_read_inferior_memory (memaddr, myaddr, len) CORE_ADDR memaddr; @@ -1127,6 +1406,7 @@ fast_but_for_the_pause_e7000_read_inferior_memory (memaddr, myaddr, len) { int loop; int c; + char buf[200]; if (((memaddr - 1) + len) < memaddr) { @@ -1134,7 +1414,8 @@ fast_but_for_the_pause_e7000_read_inferior_memory (memaddr, myaddr, len) return 0; } - printf_e7000debug ("is %x@%x:s\r", memaddr, len); + sprintf (buf, "is %x@%x:s\r", memaddr, len); + puts_e7000debug (buf); gch (); c = gch (); if (c != ENQ) @@ -1151,6 +1432,7 @@ fast_but_for_the_pause_e7000_read_inferior_memory (memaddr, myaddr, len) int length; int addr; int i; + c = gch (); switch (c) { @@ -1178,6 +1460,7 @@ fast_but_for_the_pause_e7000_read_inferior_memory (memaddr, myaddr, len) case '3': { int alen; + alen = type - '0' + 1; addr = 0; while (alen--) @@ -1187,14 +1470,14 @@ fast_but_for_the_pause_e7000_read_inferior_memory (memaddr, myaddr, len) } for (i = 0; i < length - 1; i++) - { - myaddr[i + addr - memaddr] = gbyte (); - } + myaddr[i + addr - memaddr] = gbyte (); + gbyte (); /* Ignore checksum */ } } } } + putchar_e7000 (ACK); expect ("TOP ADDRESS ="); expect ("END ADDRESS ="); @@ -1214,13 +1497,11 @@ e7000_xfer_inferior_memory (memaddr, myaddr, len, write, target) struct target_ops *target; /* ignored */ { if (write) - { - return e7000_write_inferior_memory( memaddr, myaddr, len); - } + return e7000_write_inferior_memory (memaddr, myaddr, len); + else if (len < 16) + return e7000_read_inferior_memory (memaddr, myaddr, len); else - { - return e7000_read_inferior_memory( memaddr, myaddr, len); - } + return e7000_read_inferior_memory_large (memaddr, myaddr, len); } static void @@ -1228,7 +1509,188 @@ e7000_kill (args, from_tty) char *args; int from_tty; { +} + +static void +e7000_load (args, from_tty) + char *args; + int from_tty; +{ + struct cleanup *old_chain; + asection *section; + bfd *pbfd; + bfd_vma entry; +#define WRITESIZE 0x1000 + char buf[2 + 4 + 4 + WRITESIZE]; /* `DT' + + + */ + char *filename; + int quiet; + int nostart; + time_t start_time, end_time; /* Start and end times of download */ + unsigned long data_count; /* Number of bytes transferred to memory */ + int oldtimeout = timeout; + + timeout = remote_timeout; + + /* FIXME! change test to test for type of download */ + if (!using_tcp) + { + generic_load (args, from_tty); + return; + } + + /* for direct tcp connections, we can do a fast binary download */ + buf[0] = 'D'; + buf[1] = 'T'; + quiet = 0; + nostart = 0; + filename = NULL; + + while (*args != '\000') + { + char *arg; + + while (isspace (*args)) + args++; + + arg = args; + + while ((*args != '\000') && !isspace (*args)) + args++; + + if (*args != '\000') + *args++ = '\000'; + + if (*arg != '-') + filename = arg; + else if (strncmp (arg, "-quiet", strlen (arg)) == 0) + quiet = 1; + else if (strncmp (arg, "-nostart", strlen (arg)) == 0) + nostart = 1; + else + error ("unknown option `%s'", arg); + } + + if (!filename) + filename = get_exec_file (1); + + pbfd = bfd_openr (filename, gnutarget); + if (pbfd == NULL) + { + perror_with_name (filename); + return; + } + old_chain = make_cleanup ((make_cleanup_func) bfd_close, pbfd); + + if (!bfd_check_format (pbfd, bfd_object)) + error ("\"%s\" is not an object file: %s", filename, + bfd_errmsg (bfd_get_error ())); + + start_time = time (NULL); + data_count = 0; + + puts_e7000debug ("mw\r"); + + expect ("\nOK"); + + for (section = pbfd->sections; section; section = section->next) + { + if (bfd_get_section_flags (pbfd, section) & SEC_LOAD) + { + bfd_vma section_address; + bfd_size_type section_size; + file_ptr fptr; + + section_address = bfd_get_section_vma (pbfd, section); + section_size = bfd_get_section_size_before_reloc (section); + + if (!quiet) + printf_filtered ("[Loading section %s at 0x%x (%d bytes)]\n", + bfd_get_section_name (pbfd, section), + section_address, + section_size); + + fptr = 0; + + data_count += section_size; + + while (section_size > 0) + { + int count; + static char inds[] = "|/-\\"; + static int k = 0; + + QUIT; + + count = min (section_size, WRITESIZE); + + buf[2] = section_address >> 24; + buf[3] = section_address >> 16; + buf[4] = section_address >> 8; + buf[5] = section_address; + + buf[6] = count >> 24; + buf[7] = count >> 16; + buf[8] = count >> 8; + buf[9] = count; + + bfd_get_section_contents (pbfd, section, buf + 10, fptr, count); + + if (SERIAL_WRITE (e7000_desc, buf, count + 10)) + fprintf_unfiltered (gdb_stderr, + "e7000_load: SERIAL_WRITE failed: %s\n", + safe_strerror (errno)); + + expect ("OK"); + + if (!quiet) + { + printf_unfiltered ("\r%c", inds[k++ % 4]); + gdb_flush (gdb_stdout); + } + + section_address += count; + fptr += count; + section_size -= count; + } + } + } + + write_e7000 ("ED"); + + expect_prompt (); + + end_time = time (NULL); + +/* 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 (); + + if (!nostart) + { + entry = bfd_get_start_address (pbfd); + + if (!quiet) + printf_unfiltered ("[Starting %s at 0x%x]\n", filename, entry); + +/* start_routine (entry); */ + } + + report_transfer_performance (data_count, start_time, end_time); + + do_cleanups (old_chain); + timeout = oldtimeout; } /* Clean up when a program exits. @@ -1245,10 +1707,16 @@ e7000_mourn_inferior () generic_mourn_inferior (); /* Do all the proper things now */ } -#define MAX_E7000DEBUG_BREAKPOINTS 200 +#define MAX_BREAKPOINTS 200 +#ifdef HARD_BREAKPOINTS +#define MAX_E7000DEBUG_BREAKPOINTS (BC_BREAKPOINTS ? 5 : MAX_BREAKPOINTS) +#else +#define MAX_E7000DEBUG_BREAKPOINTS MAX_BREAKPOINTS +#endif -extern int memory_breakpoint_size; -static CORE_ADDR breakaddr[MAX_E7000DEBUG_BREAKPOINTS] = +/* Since we can change to soft breakpoints dynamically, we must define + more than enough. Was breakaddr[MAX_E7000DEBUG_BREAKPOINTS]. */ +static CORE_ADDR breakaddr[MAX_BREAKPOINTS] = {0}; static int @@ -1257,22 +1725,42 @@ e7000_insert_breakpoint (addr, shadow) unsigned char *shadow; { int i; - static char nop[2] = - {0x20, 0x0b}; + char buf[200]; +#if 0 + static char nop[2] = NOP; +#endif for (i = 0; i <= MAX_E7000DEBUG_BREAKPOINTS; i++) if (breakaddr[i] == 0) { breakaddr[i] = addr; /* Save old contents, and insert a nop in the space */ +#ifdef HARD_BREAKPOINTS + if (BC_BREAKPOINTS) + { + sprintf (buf, "BC%d A=%x\r", i + 1, addr); + puts_e7000debug (buf); + } + else + { + sprintf (buf, "B %x\r", addr); + puts_e7000debug (buf); + } +#else +#if 0 e7000_read_inferior_memory (addr, shadow, 2); e7000_write_inferior_memory (addr, nop, 2); - printf_e7000debug ("B %x\r", addr); +#endif + + sprintf (buf, "B %x\r", addr); + puts_e7000debug (buf); +#endif expect_prompt (); return 0; } - error("Too many breakpoints ( > %d) for the E7000\n", MAX_E7000DEBUG_BREAKPOINTS); + error ("Too many breakpoints ( > %d) for the E7000\n", + MAX_E7000DEBUG_BREAKPOINTS); return 1; } @@ -1282,142 +1770,333 @@ e7000_remove_breakpoint (addr, shadow) unsigned char *shadow; { int i; + char buf[200]; for (i = 0; i < MAX_E7000DEBUG_BREAKPOINTS; i++) if (breakaddr[i] == addr) { breakaddr[i] = 0; - printf_e7000debug ("B - %x\r", addr); +#ifdef HARD_BREAKPOINTS + if (BC_BREAKPOINTS) + { + sprintf (buf, "BC%d - \r", i + 1); + puts_e7000debug (buf); + } + else + { + sprintf (buf, "B - %x\r", addr); + puts_e7000debug (buf); + } + expect_prompt (); +#else + sprintf (buf, "B - %x\r", addr); + puts_e7000debug (buf); expect_prompt (); + +#if 0 /* Replace the insn under the break */ e7000_write_inferior_memory (addr, shadow, 2); +#endif +#endif + return 0; } - fprintf (stderr, "Can't find breakpoint associated with 0x%x\n", addr); + warning ("Can't find breakpoint associated with 0x%x\n", addr); return 1; } - -/* Put a command string, in args, out to STDBUG. Output from STDBUG is placed - on the users terminal until the prompt is seen. */ +/* Put a command string, in args, out to STDBUG. Output from STDBUG + is placed on the users terminal until the prompt is seen. */ static void e7000_command (args, fromtty) char *args; int fromtty; { + /* FIXME: arbitrary limit on length of args. */ + char buf[200]; + + echo = 0; if (!e7000_desc) error ("e7000 target not open."); if (!args) { - printf_e7000debug ("\r"); + puts_e7000debug ("\r"); } else { - printf_e7000debug ("%s\r", args); + sprintf (buf, "%s\r", args); + puts_e7000debug (buf); } - echo_index++; + + echo++; + ctrl_c = 2; expect_full_prompt (); - echo_index--; + echo--; + ctrl_c = 0; printf_unfiltered ("\n"); -} -static void -e7000_load (args, fromtty) - char *args; - int fromtty; -{ - load_target_image (args, fromtty); + /* Who knows what the command did... */ + registers_changed (); } + static void -e7000_drain (args, fromtty) +e7000_drain_command (args, fromtty) char *args; int fromtty; { int c; - while ((c = SERIAL_READCHAR (e7000_desc, 2) != SERIAL_TIMEOUT)) + puts_e7000debug ("end\r"); + putchar_e7000 (CTRLC); + + while ((c = readchar (1) != -1)) { + if (quit_flag) + { + putchar_e7000 (CTRLC); + quit_flag = 0; + } if (c > ' ' && c < 127) - printf ("%c", c & 0xff); + printf_unfiltered ("%c", c & 0xff); else - printf ("<%x>", c & 0xff); + printf_unfiltered ("<%x>", c & 0xff); } } -e7000_noecho () -{ - echo = !echo; -} - -/* Wait until the remote machine stops, then return, - storing status in STATUS just as `wait' would. */ +#define NITEMS 7 static int -e7000_wait (pid, status) - int pid; - WAITTYPE *status; +why_stop () { + static char *strings[NITEMS] = + { + "STEP NORMAL", + "BREAK POINT", + "BREAK KEY", + "BREAK CONDI", + "CYCLE ACCESS", + "ILLEGAL INSTRUCTION", + "WRITE PROTECT", + }; + char *p[NITEMS]; int c; - int regno; - int loop = 1; - int time = 0; - WSETSTOP ((*status), 0); - /* Then echo chars until PC= string seen */ - gch (); /* Drop cr */ - gch (); /* and space */ - while (loop) + int i; + + for (i = 0; i < NITEMS; ++i) + p[i] = strings[i]; + + c = gch (); + while (1) { - c = SERIAL_READCHAR (e7000_desc, 1); - if (c < 0) + for (i = 0; i < NITEMS; i++) { - time++; - if (time == 5) + if (c == *(p[i])) { - printf_unfiltered ("[waiting for e7000..]\n"); - time = 0; + p[i]++; + if (*(p[i]) == 0) + { + /* found one of the choices */ + return i; + } } + else + p[i] = strings[i]; } + + c = gch (); + } +} + +/* Suck characters, if a string match, then return the strings index + otherwise echo them. */ + +int +expect_n (strings) + char **strings; +{ + char *(ptr[10]); + int n; + int c; + char saveaway[100]; + char *buffer = saveaway; + /* Count number of expect strings */ + + for (n = 0; strings[n]; n++) + { + ptr[n] = strings[n]; + } + + while (1) + { + int i; + int gotone = 0; + + c = readchar (1); + if (c == -1) + { + printf_unfiltered ("[waiting for e7000...]\n"); + } +#ifdef __GO32__ + if (kbhit ()) + { + int k = getkey (); + + if (k == 1) + quit_flag = 1; + } +#endif if (quit_flag) { + putchar_e7000 (CTRLC); /* interrupt the running program */ quit_flag = 0; - putchar_e7000 (CTRLC); /* interrupt the running program */ } - if (c == 'P') + + for (i = 0; i < n; i++) { - c = SERIAL_READCHAR (e7000_desc, 1); - if (c == 'C') + if (c == ptr[i][0]) { - c = SERIAL_READCHAR (e7000_desc, 1); - if (c == '=') - { - /* Got break */ - loop = 0; - } - else + ptr[i]++; + if (ptr[i][0] == 0) { - printf ("PC"); + /* Gone all the way */ + return i; } + gotone = 1; } else { - printf ("P"); + ptr[i] = strings[i]; } } + + if (gotone) + { + /* Save it up incase we find that there was no match */ + *buffer++ = c; + } else { - if (c > 0) + if (buffer != saveaway) { - putchar (c); - fflush (stdout); + *buffer++ = 0; + printf_unfiltered ("%s", buffer); + buffer = saveaway; + } + if (c != -1) + { + putchar_unfiltered (c); + gdb_flush (gdb_stdout); } } } - fetch_regs_from_dump (gch, want_nopc); +} + +/* We subtract two from the pc here rather than use + DECR_PC_AFTER_BREAK since the e7000 doesn't always add two to the + pc, and the simulators never do. */ + +static void +sub2_from_pc () +{ + char buf[4]; + char buf2[200]; + + store_signed_integer (buf, + REGISTER_RAW_SIZE (PC_REGNUM), + read_register (PC_REGNUM) - 2); + supply_register (PC_REGNUM, buf); + sprintf (buf2, ".PC %x\r", read_register (PC_REGNUM)); + puts_e7000debug (buf2); +} + +#define WAS_SLEEP 0 +#define WAS_INT 1 +#define WAS_RUNNING 2 +#define WAS_OTHER 3 + +static char *estrings[] = +{ + "** SLEEP", + "BREAK !", + "** PC", + "PC", + NULL +}; + +/* Wait until the remote machine stops, then return, storing status in + STATUS just as `wait' would. */ + +static int +e7000_wait (pid, status) + int pid; + struct target_waitstatus *status; +{ + int stop_reason; + int regno; + int running_count = 0; + int had_sleep = 0; + int loop = 1; + char *wanted_nopc; + + /* Then echo chars until PC= string seen */ + gch (); /* Drop cr */ + gch (); /* and space */ + + while (loop) + { + switch (expect_n (estrings)) + { + case WAS_OTHER: + /* how did this happen ? */ + loop = 0; + break; + case WAS_SLEEP: + had_sleep = 1; + putchar_e7000 (CTRLC); + loop = 0; + break; + case WAS_INT: + loop = 0; + break; + case WAS_RUNNING: + running_count++; + if (running_count == 20) + { + printf_unfiltered ("[running...]\n"); + running_count = 0; + } + break; + default: + /* error? */ + break; + } + } + + /* Skip till the PC= */ + expect ("="); + +#ifdef GDB_TARGET_IS_SH + wanted_nopc = want_nopc; + if (TARGET_ARCHITECTURE->arch == bfd_arch_sh) + switch (TARGET_ARCHITECTURE->mach) + { + case bfd_mach_sh3: + case bfd_mach_sh3e: + case bfd_mach_sh4: + wanted_nopc = want_sh3_nopc; + } +#else + if (h8300smode) + wanted_nopc = want_nopc_h8300s; + else + wanted_nopc = want_nopc_h8300h; +#endif + fetch_regs_from_dump (gch, wanted_nopc); /* And supply the extra ones the simulator uses */ for (regno = NUM_REALREGS; regno < NUM_REGS; regno++) @@ -1426,77 +2105,163 @@ e7000_wait (pid, status) supply_register (regno, (char *) &buf); } + stop_reason = why_stop (); expect_full_prompt (); - WSETSTOP ((*status), SIGTRAP); + + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + + switch (stop_reason) + { + case 1: /* Breakpoint */ + write_pc (read_pc ()); /* PC is always off by 2 for breakpoints */ + status->value.sig = TARGET_SIGNAL_TRAP; + break; + case 0: /* Single step */ + status->value.sig = TARGET_SIGNAL_TRAP; + break; + case 2: /* Interrupt */ + if (had_sleep) + { + status->value.sig = TARGET_SIGNAL_TRAP; + sub2_from_pc (); + } + else + { + status->value.sig = TARGET_SIGNAL_INT; + } + break; + case 3: + break; + case 4: + printf_unfiltered ("a cycle address error?\n"); + status->value.sig = TARGET_SIGNAL_UNKNOWN; + break; + case 5: + status->value.sig = TARGET_SIGNAL_ILL; + break; + case 6: + status->value.sig = TARGET_SIGNAL_SEGV; + break; + case 7: /* Anything else (NITEMS + 1) */ + printf_unfiltered ("a write protect error?\n"); + status->value.sig = TARGET_SIGNAL_UNKNOWN; + break; + default: + /* Get the user's attention - this should never happen. */ + abort (); + } return 0; } -/* Define the target subroutine names */ +/* Stop the running program. */ -struct target_ops e7000_ops = +static void +e7000_stop () { - "e7000", - "Remote Hitachi e7000 target", - "Use a remote Hitachi e7000 ICE connected by a serial line,\n\ + /* Sending a ^C is supposed to stop the running program. */ + putchar_e7000 (CTRLC); +} + +/* Define the target subroutine names. */ + +struct target_ops e7000_ops; + +static void +init_e7000_ops (void) +{ + e7000_ops.to_shortname = "e7000"; + e7000_ops.to_longname = "Remote Hitachi e7000 target"; + e7000_ops.to_doc = "Use a remote Hitachi e7000 ICE connected by a serial line;\n\ or a network connection.\n\ Arguments are the name of the device for the serial line,\n\ the speed to connect at in bits per second.\n\ eg\n\ target e7000 /dev/ttya 9600\n\ -target e7000 foobar", - e7000_open, - e7000_close, - 0, - e7000_detach, - e7000_resume, - e7000_wait, - e7000_fetch_register, - e7000_store_register, - e7000_prepare_to_store, - e7000_xfer_inferior_memory, - e7000_files_info, - e7000_insert_breakpoint, - e7000_remove_breakpoint, /* Breakpoints */ - 0, - 0, - 0, - 0, - 0, /* Terminal handling */ - e7000_kill, - e7000_load, /* load */ - 0, /* lookup_symbol */ - e7000_create_inferior, - e7000_mourn_inferior, - 0, /* can_run */ - 0, /* notice_signals */ - process_stratum, - 0, /* next */ - 1, - 1, - 1, - 1, - 1, /* all mem, mem, stack, regs, exec */ - 0, - 0, /* Section pointers */ - OPS_MAGIC, /* Always the last thing */ +target e7000 foobar"; + e7000_ops.to_open = e7000_open; + e7000_ops.to_close = e7000_close; + e7000_ops.to_attach = 0; + e7000_ops.to_post_attach = NULL; + e7000_ops.to_require_attach = NULL; + e7000_ops.to_detach = e7000_detach; + e7000_ops.to_require_detach = NULL; + e7000_ops.to_resume = e7000_resume; + e7000_ops.to_wait = e7000_wait; + e7000_ops.to_post_wait = NULL; + e7000_ops.to_fetch_registers = e7000_fetch_register; + e7000_ops.to_store_registers = e7000_store_register; + e7000_ops.to_prepare_to_store = e7000_prepare_to_store; + e7000_ops.to_xfer_memory = e7000_xfer_inferior_memory; + e7000_ops.to_files_info = e7000_files_info; + e7000_ops.to_insert_breakpoint = e7000_insert_breakpoint; + e7000_ops.to_remove_breakpoint = e7000_remove_breakpoint; + e7000_ops.to_terminal_init = 0; + e7000_ops.to_terminal_inferior = 0; + e7000_ops.to_terminal_ours_for_output = 0; + e7000_ops.to_terminal_ours = 0; + e7000_ops.to_terminal_info = 0; + e7000_ops.to_kill = e7000_kill; + e7000_ops.to_load = e7000_load; + e7000_ops.to_lookup_symbol = 0; + e7000_ops.to_create_inferior = e7000_create_inferior; + e7000_ops.to_post_startup_inferior = NULL; + e7000_ops.to_acknowledge_created_inferior = NULL; + e7000_ops.to_clone_and_follow_inferior = NULL; + e7000_ops.to_post_follow_inferior_by_clone = NULL; + e7000_ops.to_insert_fork_catchpoint = NULL; + e7000_ops.to_remove_fork_catchpoint = NULL; + e7000_ops.to_insert_vfork_catchpoint = NULL; + e7000_ops.to_remove_vfork_catchpoint = NULL; + e7000_ops.to_has_forked = NULL; + e7000_ops.to_has_vforked = NULL; + e7000_ops.to_can_follow_vfork_prior_to_exec = NULL; + e7000_ops.to_post_follow_vfork = NULL; + e7000_ops.to_insert_exec_catchpoint = NULL; + e7000_ops.to_remove_exec_catchpoint = NULL; + e7000_ops.to_has_execd = NULL; + e7000_ops.to_reported_exec_events_per_exec_call = NULL; + e7000_ops.to_has_exited = NULL; + e7000_ops.to_mourn_inferior = e7000_mourn_inferior; + e7000_ops.to_can_run = 0; + e7000_ops.to_notice_signals = 0; + e7000_ops.to_thread_alive = 0; + e7000_ops.to_stop = e7000_stop; + e7000_ops.to_pid_to_exec_file = NULL; + e7000_ops.to_core_file_to_sym_file = NULL; + e7000_ops.to_stratum = process_stratum; + e7000_ops.DONT_USE = 0; + e7000_ops.to_has_all_memory = 1; + e7000_ops.to_has_memory = 1; + e7000_ops.to_has_stack = 1; + e7000_ops.to_has_registers = 1; + e7000_ops.to_has_execution = 1; + e7000_ops.to_sections = 0; + e7000_ops.to_sections_end = 0; + e7000_ops.to_magic = OPS_MAGIC; }; void _initialize_remote_e7000 () { + init_e7000_ops (); add_target (&e7000_ops); - add_com ("e7000 ", class_obscure, e7000_command, + + add_com ("e7000", class_obscure, e7000_command, "Send a command to the e7000 monitor."); - add_com ("ftplogin ", class_obscure, e7000_login, + add_com ("ftplogin", class_obscure, e7000_login_command, "Login to machine and change to directory."); - add_com ("ftpload ", class_obscure, e7000_ftp, + add_com ("ftpload", class_obscure, e7000_ftp_command, "Fetch and load a file from previously described place."); - add_com ("drain", class_obscure, e7000_drain, + add_com ("drain", class_obscure, e7000_drain_command, "Drain pending e7000 text buffers."); - add_com ("echo", class_obscure, e7000_noecho, "Toggle monitor echo."); + add_show_from_set (add_set_cmd ("usehardbreakpoints", no_class, + var_integer, (char *) &use_hard_breakpoints, + "Set use of hardware breakpoints for all breakpoints.\n", &setlist), + &showlist); }