1999-04-16 03:35:26 +02:00
|
|
|
|
/* Target communications support for Macraigor Systems' On-Chip Debugging
|
2002-02-10 05:08:42 +01:00
|
|
|
|
|
2004-01-18 20:26:51 +01:00
|
|
|
|
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004 Free
|
|
|
|
|
Software Foundation, Inc.
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
1999-07-07 22:19:36 +02:00
|
|
|
|
This file is part of GDB.
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
1999-07-07 22:19:36 +02:00
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
(at your option) any later version.
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
1999-07-07 22:19:36 +02:00
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
1999-07-07 22:19:36 +02:00
|
|
|
|
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., 59 Temple Place - Suite 330,
|
|
|
|
|
Boston, MA 02111-1307, USA. */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
#include "defs.h"
|
|
|
|
|
#include "gdbcore.h"
|
|
|
|
|
#include "gdb_string.h"
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include "frame.h"
|
|
|
|
|
#include "inferior.h"
|
|
|
|
|
#include "bfd.h"
|
|
|
|
|
#include "symfile.h"
|
|
|
|
|
#include "target.h"
|
2005-01-12 Andrew Cagney <cagney@gnu.org>
* exceptions.h (enum return_reason, RETURN_MASK)
(RETURN_MASK_QUIT, RETURN_MASK_ERROR, RETURN_MASK_ALL)
(return_mask, throw_exception, catch_exceptions_ftype)
(catch_exceptions_with_msg, catch_errors_ftype, catch_errors)
(catch_command_errors_ftype, catch_command_errors): Move to
exceptions.h.
* exceptions.c, exceptions.h: New files.
* top.c: Do not include <setjmp.h>.
(SIGJMP_BUF, SIGSETJMP, SIGLONGJMP, catch_return)
(throw_exception, catcher, catch_exceptions)
(catch_exceptions_with_msg, struct catch_errors_args)
(do_catch_errors, catch_errors, struct captured_command_args)
(do_captured_command, catch_command_errors): Move to exceptions.c.
* wrapper.c, wince.c, win32-nat.c, utils.c: Include "exceptions.h".
* tui/tui-interp.c, top.c, thread.c, symmisc.c: Ditto.
* symfile-mem.c, stack.c, solib.c, rs6000-nat.c: Ditto.
* remote-sds.c, remote-mips.c, remote-fileio.c: Ditto.
* remote-e7000.c, objc-lang.c, ocd.c: Ditto.
* remote.c, nto-procfs.c, monitor.c, mi/mi-main.c: Ditto.
* main.c, m32r-rom.c, infrun.c, inf-loop.c: Ditto.
* hppa-hpux-tdep.c, frame.c, event-top.c, event-loop.c: Ditto.
* corelow.c, corefile.c, cli/cli-interp.c, breakpoint.c: Ditto.
* ada-valprint.c, ada-lang.c: Ditto.
* Makefile.in (HFILES_NO_SRCDIR, COMMON_OBS): Add exceptions.h and
exceptions.o. Update all dependencies.
2005-01-12 19:31:35 +01:00
|
|
|
|
#include "exceptions.h"
|
1999-04-16 03:35:26 +02:00
|
|
|
|
#include "gdbcmd.h"
|
|
|
|
|
#include "objfiles.h"
|
|
|
|
|
#include "gdb-stabs.h"
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include "serial.h"
|
|
|
|
|
#include "ocd.h"
|
2001-03-01 02:39:22 +01:00
|
|
|
|
#include "regcache.h"
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
/* Prototypes for local functions */
|
|
|
|
|
|
2000-05-28 03:12:42 +02:00
|
|
|
|
static int ocd_read_bytes (CORE_ADDR memaddr, char *myaddr, int len);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
2003-01-18 Andrew Cagney <ac131313@redhat.com>
* ada-valprint.c: Eliminate PTR.
* breakpoint.c, corelow.c, cris-tdep.c, dbxread.c: Ditto.
* defs.h, dve3900-rom.c, dwarf2read.c, dwarfread.c: Ditto.
* exec.c, hppa-tdep.c, hpread.c, infcmd.c, mdebugread.c: Ditto.
* objfiles.c, objfiles.h, ocd.c, remote-es.c: Ditto.
* remote-mips.c, remote-sds.c, remote-vx.c: Ditto.
* solib-svr4.c, solib.c, stack.c, symfile.c, symfile.h: Ditto.
* symmisc.c, v850ice.c, xcoffread.c, cli/cli-script.c: Ditto.
2003-01-18 16:55:53 +01:00
|
|
|
|
static int ocd_start_remote (void *dummy);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
2000-05-28 03:12:42 +02:00
|
|
|
|
static int readchar (int timeout);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
2000-05-28 03:12:42 +02:00
|
|
|
|
static void ocd_interrupt (int signo);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
2000-05-28 03:12:42 +02:00
|
|
|
|
static void ocd_interrupt_twice (int signo);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
2000-05-28 03:12:42 +02:00
|
|
|
|
static void interrupt_query (void);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
2000-05-28 03:12:42 +02:00
|
|
|
|
static unsigned char *ocd_do_command (int cmd, int *statusp, int *lenp);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
2000-05-28 03:12:42 +02:00
|
|
|
|
static void ocd_put_packet (unsigned char *packet, int pktlen);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
2000-05-28 03:12:42 +02:00
|
|
|
|
static unsigned char *ocd_get_packet (int cmd, int *pktlen, int timeout);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
static struct target_ops *current_ops = NULL;
|
|
|
|
|
|
|
|
|
|
static int last_run_status;
|
|
|
|
|
|
|
|
|
|
/* Descriptor for I/O to remote machine. Initialize it to NULL so that
|
|
|
|
|
ocd_open knows that we don't have a file open when the program
|
|
|
|
|
starts. */
|
2001-07-11 19:52:32 +02:00
|
|
|
|
static struct serial *ocd_desc = NULL;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_error (char *s, int error_code)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
char buf[100];
|
|
|
|
|
|
|
|
|
|
fputs_filtered (s, gdb_stderr);
|
|
|
|
|
fputs_filtered (" ", gdb_stderr);
|
|
|
|
|
|
|
|
|
|
switch (error_code)
|
|
|
|
|
{
|
1999-07-07 22:19:36 +02:00
|
|
|
|
case 0x1:
|
|
|
|
|
s = "Unknown fault";
|
|
|
|
|
break;
|
|
|
|
|
case 0x2:
|
|
|
|
|
s = "Power failed";
|
|
|
|
|
break;
|
|
|
|
|
case 0x3:
|
|
|
|
|
s = "Cable disconnected";
|
|
|
|
|
break;
|
|
|
|
|
case 0x4:
|
|
|
|
|
s = "Couldn't enter OCD mode";
|
|
|
|
|
break;
|
|
|
|
|
case 0x5:
|
|
|
|
|
s = "Target stuck in reset";
|
|
|
|
|
break;
|
|
|
|
|
case 0x6:
|
|
|
|
|
s = "OCD hasn't been initialized";
|
|
|
|
|
break;
|
|
|
|
|
case 0x7:
|
|
|
|
|
s = "Write verify failed";
|
|
|
|
|
break;
|
|
|
|
|
case 0x8:
|
|
|
|
|
s = "Reg buff error (during MPC5xx fp reg read/write)";
|
|
|
|
|
break;
|
|
|
|
|
case 0x9:
|
|
|
|
|
s = "Invalid CPU register access attempt failed";
|
|
|
|
|
break;
|
|
|
|
|
case 0x11:
|
|
|
|
|
s = "Bus error";
|
|
|
|
|
break;
|
|
|
|
|
case 0x12:
|
|
|
|
|
s = "Checksum error";
|
|
|
|
|
break;
|
|
|
|
|
case 0x13:
|
|
|
|
|
s = "Illegal command";
|
|
|
|
|
break;
|
|
|
|
|
case 0x14:
|
|
|
|
|
s = "Parameter error";
|
|
|
|
|
break;
|
|
|
|
|
case 0x15:
|
|
|
|
|
s = "Internal error";
|
|
|
|
|
break;
|
|
|
|
|
case 0x80:
|
|
|
|
|
s = "Flash erase error";
|
|
|
|
|
break;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
default:
|
|
|
|
|
sprintf (buf, "Unknown error code %d", error_code);
|
|
|
|
|
s = buf;
|
|
|
|
|
}
|
|
|
|
|
|
2003-08-05 04:44:50 +02:00
|
|
|
|
error ("%s", s);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return nonzero if the thread TH is still alive on the remote system. */
|
|
|
|
|
|
|
|
|
|
int
|
2001-05-04 06:15:33 +02:00
|
|
|
|
ocd_thread_alive (ptid_t th)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clean up connection to a remote debugger. */
|
|
|
|
|
|
|
|
|
|
void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_close (int quitting)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
if (ocd_desc)
|
2001-07-15 22:34:14 +02:00
|
|
|
|
serial_close (ocd_desc);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
ocd_desc = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Stub for catch_errors. */
|
|
|
|
|
|
|
|
|
|
static int
|
2003-01-18 Andrew Cagney <ac131313@redhat.com>
* ada-valprint.c: Eliminate PTR.
* breakpoint.c, corelow.c, cris-tdep.c, dbxread.c: Ditto.
* defs.h, dve3900-rom.c, dwarf2read.c, dwarfread.c: Ditto.
* exec.c, hppa-tdep.c, hpread.c, infcmd.c, mdebugread.c: Ditto.
* objfiles.c, objfiles.h, ocd.c, remote-es.c: Ditto.
* remote-mips.c, remote-sds.c, remote-vx.c: Ditto.
* solib-svr4.c, solib.c, stack.c, symfile.c, symfile.h: Ditto.
* symmisc.c, v850ice.c, xcoffread.c, cli/cli-script.c: Ditto.
2003-01-18 16:55:53 +01:00
|
|
|
|
ocd_start_remote (void *dummy)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned char buf[10], *p;
|
|
|
|
|
int pktlen;
|
|
|
|
|
int status;
|
|
|
|
|
int error_code;
|
|
|
|
|
int speed;
|
|
|
|
|
enum ocd_target_type target_type;
|
|
|
|
|
|
1999-07-07 22:19:36 +02:00
|
|
|
|
target_type = *(enum ocd_target_type *) dummy;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
2000-09-01 02:12:10 +02:00
|
|
|
|
immediate_quit++; /* Allow user to interrupt it */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
2001-07-15 22:34:14 +02:00
|
|
|
|
serial_send_break (ocd_desc); /* Wake up the wiggler */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
speed = 80; /* Divide clock by 4000 */
|
|
|
|
|
|
|
|
|
|
buf[0] = OCD_INIT;
|
|
|
|
|
buf[1] = speed >> 8;
|
|
|
|
|
buf[2] = speed & 0xff;
|
|
|
|
|
buf[3] = target_type;
|
|
|
|
|
ocd_put_packet (buf, 4); /* Init OCD params */
|
|
|
|
|
p = ocd_get_packet (buf[0], &pktlen, remote_timeout);
|
|
|
|
|
|
|
|
|
|
if (pktlen < 2)
|
|
|
|
|
error ("Truncated response packet from OCD device");
|
|
|
|
|
|
|
|
|
|
status = p[1];
|
|
|
|
|
error_code = p[2];
|
|
|
|
|
|
|
|
|
|
if (error_code != 0)
|
|
|
|
|
ocd_error ("OCD_INIT:", error_code);
|
|
|
|
|
|
|
|
|
|
ocd_do_command (OCD_AYT, &status, &pktlen);
|
|
|
|
|
|
|
|
|
|
p = ocd_do_command (OCD_GET_VERSION, &status, &pktlen);
|
|
|
|
|
|
|
|
|
|
printf_unfiltered ("[Wiggler version %x.%x, capability 0x%x]\n",
|
|
|
|
|
p[0], p[1], (p[2] << 16) | p[3]);
|
|
|
|
|
|
|
|
|
|
/* If processor is still running, stop it. */
|
|
|
|
|
|
|
|
|
|
if (!(status & OCD_FLAG_BDM))
|
|
|
|
|
ocd_stop ();
|
|
|
|
|
|
|
|
|
|
/* When using a target box, we want to asynchronously return status when
|
|
|
|
|
target stops. The OCD_SET_CTL_FLAGS command is ignored by Wigglers.dll
|
|
|
|
|
when using a parallel Wiggler */
|
|
|
|
|
buf[0] = OCD_SET_CTL_FLAGS;
|
|
|
|
|
buf[1] = 0;
|
|
|
|
|
buf[2] = 1;
|
|
|
|
|
ocd_put_packet (buf, 3);
|
|
|
|
|
|
|
|
|
|
p = ocd_get_packet (buf[0], &pktlen, remote_timeout);
|
|
|
|
|
|
|
|
|
|
if (pktlen < 2)
|
|
|
|
|
error ("Truncated response packet from OCD device");
|
|
|
|
|
|
|
|
|
|
status = p[1];
|
|
|
|
|
error_code = p[2];
|
|
|
|
|
|
|
|
|
|
if (error_code != 0)
|
|
|
|
|
ocd_error ("OCD_SET_CTL_FLAGS:", error_code);
|
|
|
|
|
|
2000-09-01 02:12:10 +02:00
|
|
|
|
immediate_quit--;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
/* This is really the job of start_remote however, that makes an assumption
|
|
|
|
|
that the target is about to print out a status message of some sort. That
|
|
|
|
|
doesn't happen here (in fact, it may not be possible to get the monitor to
|
|
|
|
|
send the appropriate packet). */
|
|
|
|
|
|
|
|
|
|
flush_cached_frames ();
|
|
|
|
|
registers_changed ();
|
|
|
|
|
stop_pc = read_pc ();
|
2004-10-29 Andrew Cagney <cagney@gnu.org>
* frame.h (get_selected_frame): Add message parameter.
* frame.c (get_selected_frame): Add and use message parameter.
* stack.c (current_frame_command, return_command, locals_info)
(catch_info, args_info, up_silently_base, down_silently_base): Use
get_selected_frame with an explicit message.
* thread.c, stack.c, sh-tdep.c, sh64-tdep.c: Update.
* remote-rdp.c, remote-mips.c, remote-e7000.c: Update.
* ocd.c, mi/mi-main.c, mi/mi-cmd-stack.c: Update.
* infrun.c, inflow.c, infcmd.c, frame.c: Update.
* findvar.c, eval.c, corelow.c, bsd-kvm.c: Update.
* breakpoint.c: Update.
2004-10-29 22:23:17 +02:00
|
|
|
|
print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
buf[0] = OCD_LOG_FILE;
|
1999-07-07 22:19:36 +02:00
|
|
|
|
buf[1] = 3; /* close existing WIGGLERS.LOG */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
ocd_put_packet (buf, 2);
|
|
|
|
|
p = ocd_get_packet (buf[0], &pktlen, remote_timeout);
|
|
|
|
|
|
|
|
|
|
buf[0] = OCD_LOG_FILE;
|
1999-07-07 22:19:36 +02:00
|
|
|
|
buf[1] = 2; /* append to existing WIGGLERS.LOG */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
ocd_put_packet (buf, 2);
|
|
|
|
|
p = ocd_get_packet (buf[0], &pktlen, remote_timeout);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Open a connection to a remote debugger.
|
|
|
|
|
NAME is the filename used for communication. */
|
|
|
|
|
|
|
|
|
|
void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_open (char *name, int from_tty, enum ocd_target_type target_type,
|
|
|
|
|
struct target_ops *ops)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned char buf[10], *p;
|
|
|
|
|
int pktlen;
|
|
|
|
|
|
|
|
|
|
if (name == 0)
|
|
|
|
|
error ("To open an OCD connection, you need to specify the\n\
|
|
|
|
|
device the OCD device is attached to (e.g. /dev/ttya).");
|
|
|
|
|
|
|
|
|
|
target_preopen (from_tty);
|
|
|
|
|
|
|
|
|
|
current_ops = ops;
|
|
|
|
|
|
|
|
|
|
unpush_target (current_ops);
|
|
|
|
|
|
2002-02-24 04:59:50 +01:00
|
|
|
|
ocd_desc = serial_open (name);
|
|
|
|
|
if (!ocd_desc)
|
|
|
|
|
perror_with_name (name);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
if (baud_rate != -1)
|
|
|
|
|
{
|
2001-07-15 22:34:14 +02:00
|
|
|
|
if (serial_setbaudrate (ocd_desc, baud_rate))
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
2001-07-15 22:34:14 +02:00
|
|
|
|
serial_close (ocd_desc);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
perror_with_name (name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-07-15 22:34:14 +02:00
|
|
|
|
serial_raw (ocd_desc);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
/* If there is something sitting in the buffer we might take it as a
|
|
|
|
|
response to a command, which would be bad. */
|
2001-07-15 22:34:14 +02:00
|
|
|
|
serial_flush_input (ocd_desc);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
if (from_tty)
|
|
|
|
|
{
|
|
|
|
|
puts_filtered ("Remote target wiggler connected to ");
|
|
|
|
|
puts_filtered (name);
|
|
|
|
|
puts_filtered ("\n");
|
|
|
|
|
}
|
|
|
|
|
push_target (current_ops); /* Switch to using remote target now */
|
|
|
|
|
|
|
|
|
|
/* Without this, some commands which require an active target (such as kill)
|
|
|
|
|
won't work. This variable serves (at least) double duty as both the pid
|
|
|
|
|
of the target process (if it has such), and as a flag indicating that a
|
|
|
|
|
target is active. These functions should be split out into seperate
|
|
|
|
|
variables, especially since GDB will someday have a notion of debugging
|
|
|
|
|
several processes. */
|
|
|
|
|
|
2001-05-04 06:15:33 +02:00
|
|
|
|
inferior_ptid = pid_to_ptid (42000);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
/* 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 (ocd_start_remote, &target_type,
|
|
|
|
|
"Couldn't establish connection to remote target\n",
|
|
|
|
|
RETURN_MASK_ALL))
|
|
|
|
|
{
|
1999-07-07 22:19:36 +02:00
|
|
|
|
pop_target ();
|
1999-04-16 03:35:26 +02:00
|
|
|
|
error ("Failed to connect to OCD.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This takes a program previously attached to and detaches it. After
|
|
|
|
|
this is done, GDB can be used to debug some other program. We
|
|
|
|
|
better not have left any breakpoints in the target program or it'll
|
|
|
|
|
die when it hits one. */
|
|
|
|
|
|
|
|
|
|
void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_detach (char *args, int from_tty)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
if (args)
|
|
|
|
|
error ("Argument given to \"detach\" when remotely debugging.");
|
|
|
|
|
|
|
|
|
|
pop_target ();
|
|
|
|
|
if (from_tty)
|
|
|
|
|
puts_filtered ("Ending remote debugging.\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Tell the remote machine to resume. */
|
|
|
|
|
|
|
|
|
|
void
|
2001-05-04 06:15:33 +02:00
|
|
|
|
ocd_resume (ptid_t ptid, int step, enum target_signal siggnal)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
int pktlen;
|
|
|
|
|
|
|
|
|
|
if (step)
|
|
|
|
|
ocd_do_command (OCD_STEP, &last_run_status, &pktlen);
|
|
|
|
|
else
|
|
|
|
|
ocd_do_command (OCD_RUN, &last_run_status, &pktlen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_stop (void)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
int status;
|
|
|
|
|
int pktlen;
|
|
|
|
|
|
|
|
|
|
ocd_do_command (OCD_STOP, &status, &pktlen);
|
|
|
|
|
|
|
|
|
|
if (!(status & OCD_FLAG_BDM))
|
|
|
|
|
error ("Can't stop target via BDM");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static volatile int ocd_interrupt_flag;
|
|
|
|
|
|
|
|
|
|
/* Send ^C to target to halt it. Target will respond, and send us a
|
|
|
|
|
packet. */
|
|
|
|
|
|
|
|
|
|
static void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_interrupt (int signo)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
/* If this doesn't work, try more severe steps. */
|
|
|
|
|
signal (signo, ocd_interrupt_twice);
|
1999-07-07 22:19:36 +02:00
|
|
|
|
|
1999-04-16 03:35:26 +02:00
|
|
|
|
if (remote_debug)
|
|
|
|
|
printf_unfiltered ("ocd_interrupt called\n");
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
char buf[1];
|
|
|
|
|
|
|
|
|
|
ocd_stop ();
|
|
|
|
|
buf[0] = OCD_AYT;
|
|
|
|
|
ocd_put_packet (buf, 1);
|
|
|
|
|
ocd_interrupt_flag = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-07-07 22:19:36 +02:00
|
|
|
|
static void (*ofunc) ();
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
/* The user typed ^C twice. */
|
|
|
|
|
static void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_interrupt_twice (int signo)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
signal (signo, ofunc);
|
1999-07-07 22:19:36 +02:00
|
|
|
|
|
1999-04-16 03:35:26 +02:00
|
|
|
|
interrupt_query ();
|
|
|
|
|
|
|
|
|
|
signal (signo, ocd_interrupt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Ask the user what to do when an interrupt is received. */
|
|
|
|
|
|
|
|
|
|
static void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
interrupt_query (void)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
target_terminal_ours ();
|
|
|
|
|
|
|
|
|
|
if (query ("Interrupted while waiting for the program.\n\
|
|
|
|
|
Give up (and stop debugging it)? "))
|
|
|
|
|
{
|
|
|
|
|
target_mourn_inferior ();
|
2002-02-10 05:08:42 +01:00
|
|
|
|
throw_exception (RETURN_QUIT);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
target_terminal_inferior ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If nonzero, ignore the next kill. */
|
|
|
|
|
static int kill_kludge;
|
|
|
|
|
|
|
|
|
|
/* Wait until the remote machine stops, then return,
|
|
|
|
|
storing status in STATUS just as `wait' would.
|
|
|
|
|
Returns "pid" (though it's not clear what, if anything, that
|
|
|
|
|
means in the case of this target). */
|
|
|
|
|
|
|
|
|
|
int
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_wait (void)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned char *p;
|
|
|
|
|
int error_code;
|
|
|
|
|
int pktlen;
|
|
|
|
|
char buf[1];
|
|
|
|
|
|
|
|
|
|
ocd_interrupt_flag = 0;
|
|
|
|
|
|
|
|
|
|
/* Target might already be stopped by the time we get here. */
|
|
|
|
|
/* If we aren't already stopped, we need to loop until we've dropped
|
|
|
|
|
back into BDM mode */
|
|
|
|
|
|
|
|
|
|
while (!(last_run_status & OCD_FLAG_BDM))
|
|
|
|
|
{
|
|
|
|
|
buf[0] = OCD_AYT;
|
|
|
|
|
ocd_put_packet (buf, 1);
|
|
|
|
|
p = ocd_get_packet (OCD_AYT, &pktlen, -1);
|
|
|
|
|
|
|
|
|
|
ofunc = (void (*)()) signal (SIGINT, ocd_interrupt);
|
|
|
|
|
signal (SIGINT, ofunc);
|
|
|
|
|
|
|
|
|
|
if (pktlen < 2)
|
|
|
|
|
error ("Truncated response packet from OCD device");
|
|
|
|
|
|
|
|
|
|
last_run_status = p[1];
|
|
|
|
|
error_code = p[2];
|
|
|
|
|
|
|
|
|
|
if (error_code != 0)
|
|
|
|
|
ocd_error ("target_wait:", error_code);
|
|
|
|
|
|
|
|
|
|
if (last_run_status & OCD_FLAG_PWF)
|
|
|
|
|
error ("OCD device lost VCC at BDM interface.");
|
|
|
|
|
else if (last_run_status & OCD_FLAG_CABLE_DISC)
|
|
|
|
|
error ("OCD device cable appears to have been disconnected.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ocd_interrupt_flag)
|
|
|
|
|
return 1;
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read registers from the OCD device. Specify the starting and ending
|
|
|
|
|
register number. Return the number of regs actually read in *NUMREGS.
|
|
|
|
|
Returns a pointer to a static array containing the register contents. */
|
|
|
|
|
|
|
|
|
|
unsigned char *
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_read_bdm_registers (int first_bdm_regno, int last_bdm_regno, int *reglen)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned char buf[10];
|
|
|
|
|
int i;
|
|
|
|
|
unsigned char *p;
|
|
|
|
|
unsigned char *regs;
|
|
|
|
|
int error_code, status;
|
|
|
|
|
int pktlen;
|
|
|
|
|
|
|
|
|
|
buf[0] = OCD_READ_REGS;
|
|
|
|
|
buf[1] = first_bdm_regno >> 8;
|
|
|
|
|
buf[2] = first_bdm_regno & 0xff;
|
|
|
|
|
buf[3] = last_bdm_regno >> 8;
|
|
|
|
|
buf[4] = last_bdm_regno & 0xff;
|
|
|
|
|
|
|
|
|
|
ocd_put_packet (buf, 5);
|
|
|
|
|
p = ocd_get_packet (OCD_READ_REGS, &pktlen, remote_timeout);
|
|
|
|
|
|
|
|
|
|
status = p[1];
|
|
|
|
|
error_code = p[2];
|
|
|
|
|
|
|
|
|
|
if (error_code != 0)
|
|
|
|
|
ocd_error ("read_bdm_registers:", error_code);
|
|
|
|
|
|
|
|
|
|
i = p[3];
|
|
|
|
|
if (i == 0)
|
|
|
|
|
i = 256;
|
|
|
|
|
|
|
|
|
|
if (i > pktlen - 4
|
|
|
|
|
|| ((i & 3) != 0))
|
|
|
|
|
error ("Register block size bad: %d", i);
|
|
|
|
|
|
|
|
|
|
*reglen = i;
|
|
|
|
|
|
|
|
|
|
regs = p + 4;
|
|
|
|
|
|
|
|
|
|
return regs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read register BDM_REGNO and returns its value ala read_register() */
|
|
|
|
|
|
|
|
|
|
CORE_ADDR
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_read_bdm_register (int bdm_regno)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
int reglen;
|
|
|
|
|
unsigned char *p;
|
|
|
|
|
CORE_ADDR regval;
|
|
|
|
|
|
|
|
|
|
p = ocd_read_bdm_registers (bdm_regno, bdm_regno, ®len);
|
|
|
|
|
regval = extract_unsigned_integer (p, reglen);
|
|
|
|
|
|
|
|
|
|
return regval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_write_bdm_registers (int first_bdm_regno, unsigned char *regptr, int reglen)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned char *buf;
|
|
|
|
|
unsigned char *p;
|
|
|
|
|
int error_code, status;
|
|
|
|
|
int pktlen;
|
|
|
|
|
|
|
|
|
|
buf = alloca (4 + reglen);
|
|
|
|
|
|
|
|
|
|
buf[0] = OCD_WRITE_REGS;
|
|
|
|
|
buf[1] = first_bdm_regno >> 8;
|
|
|
|
|
buf[2] = first_bdm_regno & 0xff;
|
|
|
|
|
buf[3] = reglen;
|
|
|
|
|
memcpy (buf + 4, regptr, reglen);
|
|
|
|
|
|
|
|
|
|
ocd_put_packet (buf, 4 + reglen);
|
|
|
|
|
p = ocd_get_packet (OCD_WRITE_REGS, &pktlen, remote_timeout);
|
|
|
|
|
|
|
|
|
|
if (pktlen < 3)
|
|
|
|
|
error ("Truncated response packet from OCD device");
|
|
|
|
|
|
|
|
|
|
status = p[1];
|
|
|
|
|
error_code = p[2];
|
|
|
|
|
|
|
|
|
|
if (error_code != 0)
|
|
|
|
|
ocd_error ("ocd_write_bdm_registers:", error_code);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_write_bdm_register (int bdm_regno, CORE_ADDR reg)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned char buf[4];
|
|
|
|
|
|
|
|
|
|
store_unsigned_integer (buf, 4, reg);
|
|
|
|
|
|
|
|
|
|
ocd_write_bdm_registers (bdm_regno, buf, 4);
|
|
|
|
|
}
|
|
|
|
|
|
1999-07-07 22:19:36 +02:00
|
|
|
|
void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_prepare_to_store (void)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write memory data directly to the remote machine.
|
|
|
|
|
This does not inform the data cache; the data cache uses this.
|
|
|
|
|
MEMADDR is the address in the remote memory space.
|
|
|
|
|
MYADDR is the address of the buffer in our space.
|
|
|
|
|
LEN is the number of bytes.
|
|
|
|
|
|
|
|
|
|
Returns number of bytes transferred, or 0 for error. */
|
|
|
|
|
|
|
|
|
|
static int write_mem_command = OCD_WRITE_MEM;
|
|
|
|
|
|
|
|
|
|
int
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_write_bytes (CORE_ADDR memaddr, char *myaddr, int len)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
char buf[256 + 10];
|
|
|
|
|
unsigned char *p;
|
|
|
|
|
int origlen;
|
|
|
|
|
|
|
|
|
|
origlen = len;
|
|
|
|
|
|
|
|
|
|
buf[0] = write_mem_command;
|
|
|
|
|
buf[5] = 1; /* Write as bytes */
|
|
|
|
|
buf[6] = 0; /* Don't verify */
|
|
|
|
|
|
|
|
|
|
while (len > 0)
|
|
|
|
|
{
|
|
|
|
|
int numbytes;
|
|
|
|
|
int pktlen;
|
|
|
|
|
int status, error_code;
|
|
|
|
|
|
|
|
|
|
numbytes = min (len, 256 - 8);
|
|
|
|
|
|
|
|
|
|
buf[1] = memaddr >> 24;
|
|
|
|
|
buf[2] = memaddr >> 16;
|
|
|
|
|
buf[3] = memaddr >> 8;
|
|
|
|
|
buf[4] = memaddr;
|
|
|
|
|
|
|
|
|
|
buf[7] = numbytes;
|
|
|
|
|
|
|
|
|
|
memcpy (&buf[8], myaddr, numbytes);
|
|
|
|
|
ocd_put_packet (buf, 8 + numbytes);
|
|
|
|
|
p = ocd_get_packet (OCD_WRITE_MEM, &pktlen, remote_timeout);
|
|
|
|
|
if (pktlen < 3)
|
|
|
|
|
error ("Truncated response packet from OCD device");
|
|
|
|
|
|
|
|
|
|
status = p[1];
|
|
|
|
|
error_code = p[2];
|
|
|
|
|
|
|
|
|
|
if (error_code == 0x11) /* Got a bus error? */
|
|
|
|
|
{
|
|
|
|
|
CORE_ADDR error_address;
|
|
|
|
|
|
|
|
|
|
error_address = p[3] << 24;
|
|
|
|
|
error_address |= p[4] << 16;
|
|
|
|
|
error_address |= p[5] << 8;
|
|
|
|
|
error_address |= p[6];
|
|
|
|
|
numbytes = error_address - memaddr;
|
|
|
|
|
|
|
|
|
|
len -= numbytes;
|
|
|
|
|
|
|
|
|
|
errno = EIO;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else if (error_code != 0)
|
|
|
|
|
ocd_error ("ocd_write_bytes:", error_code);
|
|
|
|
|
|
|
|
|
|
len -= numbytes;
|
|
|
|
|
memaddr += numbytes;
|
|
|
|
|
myaddr += numbytes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return origlen - len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read memory data directly from the remote machine.
|
|
|
|
|
This does not use the data cache; the data cache uses this.
|
|
|
|
|
MEMADDR is the address in the remote memory space.
|
|
|
|
|
MYADDR is the address of the buffer in our space.
|
|
|
|
|
LEN is the number of bytes.
|
|
|
|
|
|
|
|
|
|
Returns number of bytes transferred, or 0 for error. */
|
|
|
|
|
|
|
|
|
|
static int
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_read_bytes (CORE_ADDR memaddr, char *myaddr, int len)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
char buf[256 + 10];
|
|
|
|
|
unsigned char *p;
|
|
|
|
|
int origlen;
|
|
|
|
|
|
|
|
|
|
origlen = len;
|
|
|
|
|
|
|
|
|
|
buf[0] = OCD_READ_MEM;
|
|
|
|
|
buf[5] = 1; /* Read as bytes */
|
|
|
|
|
|
|
|
|
|
while (len > 0)
|
|
|
|
|
{
|
|
|
|
|
int numbytes;
|
|
|
|
|
int pktlen;
|
|
|
|
|
int status, error_code;
|
|
|
|
|
|
|
|
|
|
numbytes = min (len, 256 - 7);
|
|
|
|
|
|
|
|
|
|
buf[1] = memaddr >> 24;
|
|
|
|
|
buf[2] = memaddr >> 16;
|
|
|
|
|
buf[3] = memaddr >> 8;
|
|
|
|
|
buf[4] = memaddr;
|
|
|
|
|
|
|
|
|
|
buf[6] = numbytes;
|
|
|
|
|
|
|
|
|
|
ocd_put_packet (buf, 7);
|
|
|
|
|
p = ocd_get_packet (OCD_READ_MEM, &pktlen, remote_timeout);
|
|
|
|
|
if (pktlen < 4)
|
|
|
|
|
error ("Truncated response packet from OCD device");
|
|
|
|
|
|
|
|
|
|
status = p[1];
|
|
|
|
|
error_code = p[2];
|
|
|
|
|
|
|
|
|
|
if (error_code == 0x11) /* Got a bus error? */
|
|
|
|
|
{
|
|
|
|
|
CORE_ADDR error_address;
|
|
|
|
|
|
|
|
|
|
error_address = p[3] << 24;
|
|
|
|
|
error_address |= p[4] << 16;
|
|
|
|
|
error_address |= p[5] << 8;
|
|
|
|
|
error_address |= p[6];
|
|
|
|
|
numbytes = error_address - memaddr;
|
|
|
|
|
|
|
|
|
|
len -= numbytes;
|
|
|
|
|
|
|
|
|
|
errno = EIO;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else if (error_code != 0)
|
|
|
|
|
ocd_error ("ocd_read_bytes:", error_code);
|
|
|
|
|
|
|
|
|
|
memcpy (myaddr, &p[4], numbytes);
|
|
|
|
|
|
|
|
|
|
len -= numbytes;
|
|
|
|
|
memaddr += numbytes;
|
|
|
|
|
myaddr += numbytes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return origlen - len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read or write LEN bytes from inferior memory at MEMADDR, transferring
|
|
|
|
|
to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is
|
2000-09-26 06:27:59 +02:00
|
|
|
|
nonzero. Returns length of data written or read; 0 for error. TARGET
|
|
|
|
|
is ignored. */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
int
|
2000-09-26 06:27:59 +02:00
|
|
|
|
ocd_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int should_write,
|
2001-03-05 17:38:07 +01:00
|
|
|
|
struct mem_attrib *attrib, struct target_ops *target)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
2000-11-03 23:00:56 +01:00
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
if (should_write)
|
|
|
|
|
res = ocd_write_bytes (memaddr, myaddr, len);
|
|
|
|
|
else
|
|
|
|
|
res = ocd_read_bytes (memaddr, myaddr, len);
|
|
|
|
|
|
|
|
|
|
return res;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_files_info (struct target_ops *ignore)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
puts_filtered ("Debugging a target over a serial line.\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Stuff for dealing with the packets which are part of this protocol.
|
|
|
|
|
See comment at top of file for details. */
|
|
|
|
|
|
|
|
|
|
/* Read a single character from the remote side, handling wierd errors. */
|
|
|
|
|
|
|
|
|
|
static int
|
2000-07-30 03:48:28 +02:00
|
|
|
|
readchar (int timeout)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
int ch;
|
|
|
|
|
|
2001-07-15 22:34:14 +02:00
|
|
|
|
ch = serial_readchar (ocd_desc, timeout);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
switch (ch)
|
|
|
|
|
{
|
|
|
|
|
case SERIAL_EOF:
|
|
|
|
|
error ("Remote connection closed");
|
|
|
|
|
case SERIAL_ERROR:
|
|
|
|
|
perror_with_name ("Remote communication error");
|
|
|
|
|
case SERIAL_TIMEOUT:
|
|
|
|
|
default:
|
|
|
|
|
return ch;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Send a packet to the OCD device. The packet framed by a SYN character,
|
|
|
|
|
a byte count and a checksum. The byte count only counts the number of
|
|
|
|
|
bytes between the count and the checksum. A count of zero actually
|
|
|
|
|
means 256. Any SYNs within the packet (including the checksum and
|
|
|
|
|
count) must be quoted. The quote character must be quoted as well.
|
|
|
|
|
Quoting is done by replacing the character with the two-character sequence
|
|
|
|
|
DLE, {char} | 0100. Note that the quoting mechanism has no effect on the
|
|
|
|
|
byte count. */
|
|
|
|
|
|
|
|
|
|
static void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_put_packet (unsigned char *buf, int len)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned char checksum;
|
|
|
|
|
unsigned char c;
|
|
|
|
|
unsigned char *packet, *packet_ptr;
|
|
|
|
|
|
1999-07-07 22:19:36 +02:00
|
|
|
|
packet = alloca (len + 1 + 1); /* packet + SYN + checksum */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
packet_ptr = packet;
|
|
|
|
|
|
|
|
|
|
checksum = 0;
|
|
|
|
|
|
|
|
|
|
*packet_ptr++ = 0x55;
|
|
|
|
|
|
|
|
|
|
while (len-- > 0)
|
|
|
|
|
{
|
|
|
|
|
c = *buf++;
|
|
|
|
|
|
|
|
|
|
checksum += c;
|
|
|
|
|
*packet_ptr++ = c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*packet_ptr++ = -checksum;
|
2001-07-15 22:34:14 +02:00
|
|
|
|
if (serial_write (ocd_desc, packet, packet_ptr - packet))
|
1999-04-16 03:35:26 +02:00
|
|
|
|
perror_with_name ("output_packet: write failed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get a packet from the OCD device. Timeout is only enforced for the
|
|
|
|
|
first byte of the packet. Subsequent bytes are expected to arrive in
|
|
|
|
|
time <= remote_timeout. Returns a pointer to a static buffer containing
|
|
|
|
|
the payload of the packet. *LENP contains the length of the packet.
|
1999-07-07 22:19:36 +02:00
|
|
|
|
*/
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
static unsigned char *
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_get_packet (int cmd, int *lenp, int timeout)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
int ch;
|
|
|
|
|
int len;
|
|
|
|
|
static unsigned char packet[512];
|
|
|
|
|
unsigned char *packet_ptr;
|
|
|
|
|
unsigned char checksum;
|
|
|
|
|
|
|
|
|
|
ch = readchar (timeout);
|
|
|
|
|
|
|
|
|
|
if (ch < 0)
|
|
|
|
|
error ("ocd_get_packet (readchar): %d", ch);
|
|
|
|
|
|
|
|
|
|
if (ch != 0x55)
|
|
|
|
|
error ("ocd_get_packet (readchar): %d", ch);
|
|
|
|
|
|
|
|
|
|
/* Found the start of a packet */
|
|
|
|
|
|
|
|
|
|
packet_ptr = packet;
|
|
|
|
|
checksum = 0;
|
|
|
|
|
|
|
|
|
|
/* Read command char. That sort of tells us how long the packet is. */
|
|
|
|
|
|
|
|
|
|
ch = readchar (timeout);
|
|
|
|
|
|
|
|
|
|
if (ch < 0)
|
|
|
|
|
error ("ocd_get_packet (readchar): %d", ch);
|
|
|
|
|
|
|
|
|
|
*packet_ptr++ = ch;
|
|
|
|
|
checksum += ch;
|
|
|
|
|
|
|
|
|
|
/* Get status. */
|
|
|
|
|
|
|
|
|
|
ch = readchar (timeout);
|
|
|
|
|
|
|
|
|
|
if (ch < 0)
|
|
|
|
|
error ("ocd_get_packet (readchar): %d", ch);
|
|
|
|
|
*packet_ptr++ = ch;
|
|
|
|
|
checksum += ch;
|
|
|
|
|
|
|
|
|
|
/* Get error code. */
|
|
|
|
|
|
|
|
|
|
ch = readchar (timeout);
|
|
|
|
|
|
|
|
|
|
if (ch < 0)
|
|
|
|
|
error ("ocd_get_packet (readchar): %d", ch);
|
|
|
|
|
*packet_ptr++ = ch;
|
|
|
|
|
checksum += ch;
|
|
|
|
|
|
|
|
|
|
switch (ch) /* Figure out length of packet */
|
|
|
|
|
{
|
|
|
|
|
case 0x7: /* Write verify error? */
|
|
|
|
|
len = 8; /* write address, value read back */
|
|
|
|
|
break;
|
|
|
|
|
case 0x11: /* Bus error? */
|
1999-07-07 22:19:36 +02:00
|
|
|
|
/* write address, read flag */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
case 0x15: /* Internal error */
|
|
|
|
|
len = 5; /* error code, vector */
|
|
|
|
|
break;
|
|
|
|
|
default: /* Error w/no params */
|
|
|
|
|
len = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 0x0: /* Normal result */
|
|
|
|
|
switch (packet[0])
|
|
|
|
|
{
|
1999-07-07 22:19:36 +02:00
|
|
|
|
case OCD_AYT: /* Are You There? */
|
|
|
|
|
case OCD_SET_BAUD_RATE: /* Set Baud Rate */
|
|
|
|
|
case OCD_INIT: /* Initialize OCD device */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
case OCD_SET_SPEED: /* Set Speed */
|
1999-07-07 22:19:36 +02:00
|
|
|
|
case OCD_SET_FUNC_CODE: /* Set Function Code */
|
|
|
|
|
case OCD_SET_CTL_FLAGS: /* Set Control Flags */
|
|
|
|
|
case OCD_SET_BUF_ADDR: /* Set Register Buffer Address */
|
|
|
|
|
case OCD_RUN: /* Run Target from PC */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
case OCD_RUN_ADDR: /* Run Target from Specified Address */
|
1999-07-07 22:19:36 +02:00
|
|
|
|
case OCD_STOP: /* Stop Target */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
case OCD_RESET_RUN: /* Reset Target and Run */
|
|
|
|
|
case OCD_RESET: /* Reset Target and Halt */
|
1999-07-07 22:19:36 +02:00
|
|
|
|
case OCD_STEP: /* Single Step */
|
|
|
|
|
case OCD_WRITE_REGS: /* Write Register */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
case OCD_WRITE_MEM: /* Write Memory */
|
|
|
|
|
case OCD_FILL_MEM: /* Fill Memory */
|
|
|
|
|
case OCD_MOVE_MEM: /* Move Memory */
|
1999-07-07 22:19:36 +02:00
|
|
|
|
case OCD_WRITE_INT_MEM: /* Write Internal Memory */
|
|
|
|
|
case OCD_JUMP: /* Jump to Subroutine */
|
|
|
|
|
case OCD_ERASE_FLASH: /* Erase flash memory */
|
|
|
|
|
case OCD_PROGRAM_FLASH: /* Write flash memory */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
case OCD_EXIT_MON: /* Exit the flash programming monitor */
|
|
|
|
|
case OCD_ENTER_MON: /* Enter the flash programming monitor */
|
|
|
|
|
case OCD_LOG_FILE: /* Make Wigglers.dll save Wigglers.log */
|
1999-07-07 22:19:36 +02:00
|
|
|
|
case OCD_SET_CONNECTION: /* Set type of connection in Wigglers.dll */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
len = 0;
|
|
|
|
|
break;
|
1999-07-07 22:19:36 +02:00
|
|
|
|
case OCD_GET_VERSION: /* Get Version */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
len = 10;
|
|
|
|
|
break;
|
1999-07-07 22:19:36 +02:00
|
|
|
|
case OCD_GET_STATUS_MASK: /* Get Status Mask */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
len = 1;
|
|
|
|
|
break;
|
|
|
|
|
case OCD_GET_CTRS: /* Get Error Counters */
|
|
|
|
|
case OCD_READ_REGS: /* Read Register */
|
|
|
|
|
case OCD_READ_MEM: /* Read Memory */
|
1999-07-07 22:19:36 +02:00
|
|
|
|
case OCD_READ_INT_MEM: /* Read Internal Memory */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
len = 257;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
error ("ocd_get_packet: unknown packet type 0x%x\n", ch);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (len == 257) /* Byte stream? */
|
|
|
|
|
{ /* Yes, byte streams contain the length */
|
|
|
|
|
ch = readchar (timeout);
|
|
|
|
|
|
|
|
|
|
if (ch < 0)
|
|
|
|
|
error ("ocd_get_packet (readchar): %d", ch);
|
|
|
|
|
*packet_ptr++ = ch;
|
|
|
|
|
checksum += ch;
|
|
|
|
|
len = ch;
|
|
|
|
|
if (len == 0)
|
|
|
|
|
len = 256;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (len-- >= 0) /* Do rest of packet and checksum */
|
|
|
|
|
{
|
|
|
|
|
ch = readchar (timeout);
|
|
|
|
|
|
|
|
|
|
if (ch < 0)
|
|
|
|
|
error ("ocd_get_packet (readchar): %d", ch);
|
|
|
|
|
*packet_ptr++ = ch;
|
|
|
|
|
checksum += ch;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (checksum != 0)
|
|
|
|
|
error ("ocd_get_packet: bad packet checksum");
|
|
|
|
|
|
|
|
|
|
if (cmd != -1 && cmd != packet[0])
|
|
|
|
|
error ("Response phase error. Got 0x%x, expected 0x%x", packet[0], cmd);
|
|
|
|
|
|
1999-07-07 22:19:36 +02:00
|
|
|
|
*lenp = packet_ptr - packet - 1; /* Subtract checksum byte */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
return packet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Execute a simple (one-byte) command. Returns a pointer to the data
|
|
|
|
|
following the error code. */
|
|
|
|
|
|
|
|
|
|
static unsigned char *
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_do_command (int cmd, int *statusp, int *lenp)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned char buf[100], *p;
|
|
|
|
|
int status, error_code;
|
|
|
|
|
char errbuf[100];
|
|
|
|
|
|
|
|
|
|
unsigned char logbuf[100];
|
|
|
|
|
int logpktlen;
|
|
|
|
|
|
|
|
|
|
buf[0] = cmd;
|
1999-07-07 22:19:36 +02:00
|
|
|
|
ocd_put_packet (buf, 1); /* Send command */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
p = ocd_get_packet (*buf, lenp, remote_timeout);
|
|
|
|
|
|
|
|
|
|
if (*lenp < 3)
|
|
|
|
|
error ("Truncated response packet from OCD device");
|
|
|
|
|
|
|
|
|
|
status = p[1];
|
|
|
|
|
error_code = p[2];
|
|
|
|
|
|
|
|
|
|
if (error_code != 0)
|
|
|
|
|
{
|
|
|
|
|
sprintf (errbuf, "ocd_do_command (0x%x):", cmd);
|
|
|
|
|
ocd_error (errbuf, error_code);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status & OCD_FLAG_PWF)
|
|
|
|
|
error ("OCD device can't detect VCC at BDM interface.");
|
|
|
|
|
else if (status & OCD_FLAG_CABLE_DISC)
|
|
|
|
|
error ("BDM cable appears to be disconnected.");
|
|
|
|
|
|
|
|
|
|
*statusp = status;
|
|
|
|
|
|
|
|
|
|
logbuf[0] = OCD_LOG_FILE;
|
1999-07-07 22:19:36 +02:00
|
|
|
|
logbuf[1] = 3; /* close existing WIGGLERS.LOG */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
ocd_put_packet (logbuf, 2);
|
|
|
|
|
ocd_get_packet (logbuf[0], &logpktlen, remote_timeout);
|
|
|
|
|
|
|
|
|
|
logbuf[0] = OCD_LOG_FILE;
|
1999-07-07 22:19:36 +02:00
|
|
|
|
logbuf[1] = 2; /* append to existing WIGGLERS.LOG */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
ocd_put_packet (logbuf, 2);
|
|
|
|
|
ocd_get_packet (logbuf[0], &logpktlen, remote_timeout);
|
|
|
|
|
|
|
|
|
|
return p + 3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_kill (void)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
/* For some mysterious reason, wait_for_inferior calls kill instead of
|
|
|
|
|
mourn after it gets TARGET_WAITKIND_SIGNALLED. Work around it. */
|
|
|
|
|
if (kill_kludge)
|
|
|
|
|
{
|
|
|
|
|
kill_kludge = 0;
|
|
|
|
|
target_mourn_inferior ();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Don't wait for it to die. I'm not really sure it matters whether
|
|
|
|
|
we do or not. */
|
|
|
|
|
target_mourn_inferior ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_mourn (void)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
unpush_target (current_ops);
|
|
|
|
|
generic_mourn_inferior ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* All we actually do is set the PC to the start address of exec_bfd, and start
|
|
|
|
|
the program at that point. */
|
|
|
|
|
|
|
|
|
|
void
|
2004-05-25 16:58:31 +02:00
|
|
|
|
ocd_create_inferior (char *exec_file, char *args, char **env, int from_tty)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
if (args && (*args != '\000'))
|
|
|
|
|
error ("Args are not supported by BDM.");
|
|
|
|
|
|
|
|
|
|
clear_proceed_status ();
|
|
|
|
|
proceed (bfd_get_start_address (exec_bfd), TARGET_SIGNAL_0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_load (char *args, int from_tty)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
generic_load (args, from_tty);
|
|
|
|
|
|
2001-05-04 06:15:33 +02:00
|
|
|
|
inferior_ptid = null_ptid;
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
/* 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 ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This should be defined for each target */
|
|
|
|
|
/* But we want to be able to compile this file for some configurations
|
|
|
|
|
not yet supported fully */
|
1999-07-07 22:19:36 +02:00
|
|
|
|
|
|
|
|
|
#define BDM_BREAKPOINT {0x0,0x0,0x0,0x0} /* For ppc 8xx */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
/* BDM (at least on CPU32) uses a different breakpoint */
|
|
|
|
|
|
|
|
|
|
int
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
static char break_insn[] = BDM_BREAKPOINT;
|
|
|
|
|
int val;
|
|
|
|
|
|
|
|
|
|
val = target_read_memory (addr, contents_cache, sizeof (break_insn));
|
|
|
|
|
|
|
|
|
|
if (val == 0)
|
|
|
|
|
val = target_write_memory (addr, break_insn, sizeof (break_insn));
|
|
|
|
|
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
2000-07-30 03:48:28 +02:00
|
|
|
|
ocd_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
static char break_insn[] = BDM_BREAKPOINT;
|
|
|
|
|
int val;
|
|
|
|
|
|
|
|
|
|
val = target_write_memory (addr, contents_cache, sizeof (break_insn));
|
|
|
|
|
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
bdm_command (char *args, int from_tty)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
error ("bdm command must be followed by `reset'");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
bdm_reset_command (char *args, int from_tty)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
int status, pktlen;
|
|
|
|
|
|
|
|
|
|
if (!ocd_desc)
|
|
|
|
|
error ("Not connected to OCD device.");
|
|
|
|
|
|
|
|
|
|
ocd_do_command (OCD_RESET, &status, &pktlen);
|
2000-11-03 23:00:56 +01:00
|
|
|
|
dcache_invalidate (target_dcache);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
registers_changed ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
bdm_restart_command (char *args, int from_tty)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
int status, pktlen;
|
|
|
|
|
|
|
|
|
|
if (!ocd_desc)
|
|
|
|
|
error ("Not connected to OCD device.");
|
|
|
|
|
|
|
|
|
|
ocd_do_command (OCD_RESET_RUN, &status, &pktlen);
|
|
|
|
|
last_run_status = status;
|
|
|
|
|
clear_proceed_status ();
|
|
|
|
|
wait_for_inferior ();
|
|
|
|
|
normal_stop ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Temporary replacement for target_store_registers(). This prevents
|
|
|
|
|
generic_load from trying to set the PC. */
|
|
|
|
|
|
|
|
|
|
static void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
noop_store_registers (int regno)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
bdm_update_flash_command (char *args, int from_tty)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
int status, pktlen;
|
1999-09-09 02:02:17 +02:00
|
|
|
|
struct cleanup *old_chain;
|
2000-06-04 02:41:10 +02:00
|
|
|
|
void (*store_registers_tmp) (int);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
if (!ocd_desc)
|
|
|
|
|
error ("Not connected to OCD device.");
|
|
|
|
|
|
|
|
|
|
if (!args)
|
|
|
|
|
error ("Must specify file containing new OCD code.");
|
|
|
|
|
|
1999-07-07 22:19:36 +02:00
|
|
|
|
/* old_chain = make_cleanup (flash_cleanup, 0); */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
ocd_do_command (OCD_ENTER_MON, &status, &pktlen);
|
|
|
|
|
|
|
|
|
|
ocd_do_command (OCD_ERASE_FLASH, &status, &pktlen);
|
|
|
|
|
|
|
|
|
|
write_mem_command = OCD_PROGRAM_FLASH;
|
|
|
|
|
store_registers_tmp = current_target.to_store_registers;
|
|
|
|
|
current_target.to_store_registers = noop_store_registers;
|
|
|
|
|
|
|
|
|
|
generic_load (args, from_tty);
|
|
|
|
|
|
|
|
|
|
current_target.to_store_registers = store_registers_tmp;
|
|
|
|
|
write_mem_command = OCD_WRITE_MEM;
|
|
|
|
|
|
|
|
|
|
ocd_do_command (OCD_EXIT_MON, &status, &pktlen);
|
|
|
|
|
|
1999-07-07 22:19:36 +02:00
|
|
|
|
/* discard_cleanups (old_chain); */
|
1999-04-16 03:35:26 +02:00
|
|
|
|
}
|
|
|
|
|
|
2003-06-11 15:16:30 +02:00
|
|
|
|
extern initialize_file_ftype _initialize_remote_ocd; /* -Wmissing-prototypes */
|
|
|
|
|
|
1999-04-16 03:35:26 +02:00
|
|
|
|
void
|
2000-07-30 03:48:28 +02:00
|
|
|
|
_initialize_remote_ocd (void)
|
1999-04-16 03:35:26 +02:00
|
|
|
|
{
|
|
|
|
|
extern struct cmd_list_element *cmdlist;
|
|
|
|
|
static struct cmd_list_element *ocd_cmd_list = NULL;
|
|
|
|
|
|
2004-07-26 16:53:06 +02:00
|
|
|
|
deprecated_add_show_from_set
|
|
|
|
|
(add_set_cmd ("remotetimeout", no_class,
|
|
|
|
|
var_integer, (char *) &remote_timeout,
|
|
|
|
|
"Set timeout value for remote read.\n", &setlist),
|
|
|
|
|
&showlist);
|
1999-04-16 03:35:26 +02:00
|
|
|
|
|
|
|
|
|
add_prefix_cmd ("ocd", class_obscure, bdm_command, "", &ocd_cmd_list, "ocd ",
|
|
|
|
|
0, &cmdlist);
|
|
|
|
|
|
|
|
|
|
add_cmd ("reset", class_obscure, bdm_reset_command, "", &ocd_cmd_list);
|
|
|
|
|
add_cmd ("restart", class_obscure, bdm_restart_command, "", &ocd_cmd_list);
|
|
|
|
|
add_cmd ("update-flash", class_obscure, bdm_update_flash_command, "", &ocd_cmd_list);
|
|
|
|
|
}
|