xref: /openbsd-src/gnu/usr.bin/binutils/gdb/ocd.c (revision 11efff7f3ac2b3cfeff0c0cddc14294d9b3aca4f)
1b725ae77Skettenis /* Target communications support for Macraigor Systems' On-Chip Debugging
2b725ae77Skettenis 
3b725ae77Skettenis    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004 Free
4b725ae77Skettenis    Software Foundation, Inc.
5b725ae77Skettenis 
6b725ae77Skettenis    This file is part of GDB.
7b725ae77Skettenis 
8b725ae77Skettenis    This program is free software; you can redistribute it and/or modify
9b725ae77Skettenis    it under the terms of the GNU General Public License as published by
10b725ae77Skettenis    the Free Software Foundation; either version 2 of the License, or
11b725ae77Skettenis    (at your option) any later version.
12b725ae77Skettenis 
13b725ae77Skettenis    This program is distributed in the hope that it will be useful,
14b725ae77Skettenis    but WITHOUT ANY WARRANTY; without even the implied warranty of
15b725ae77Skettenis    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16b725ae77Skettenis    GNU General Public License for more details.
17b725ae77Skettenis 
18b725ae77Skettenis    You should have received a copy of the GNU General Public License
19b725ae77Skettenis    along with this program; if not, write to the Free Software
20b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
21b725ae77Skettenis    Boston, MA 02111-1307, USA.  */
22b725ae77Skettenis 
23b725ae77Skettenis #include "defs.h"
24b725ae77Skettenis #include "gdbcore.h"
25b725ae77Skettenis #include "gdb_string.h"
26b725ae77Skettenis #include <fcntl.h>
27b725ae77Skettenis #include "frame.h"
28b725ae77Skettenis #include "inferior.h"
29b725ae77Skettenis #include "bfd.h"
30b725ae77Skettenis #include "symfile.h"
31b725ae77Skettenis #include "target.h"
32b725ae77Skettenis #include "gdbcmd.h"
33b725ae77Skettenis #include "objfiles.h"
34b725ae77Skettenis #include "gdb-stabs.h"
35b725ae77Skettenis #include <sys/types.h>
36b725ae77Skettenis #include <signal.h>
37b725ae77Skettenis #include "serial.h"
38b725ae77Skettenis #include "ocd.h"
39b725ae77Skettenis #include "regcache.h"
40b725ae77Skettenis 
41b725ae77Skettenis /* Prototypes for local functions */
42b725ae77Skettenis 
43b725ae77Skettenis static int ocd_read_bytes (CORE_ADDR memaddr, char *myaddr, int len);
44b725ae77Skettenis 
45b725ae77Skettenis static int ocd_start_remote (void *dummy);
46b725ae77Skettenis 
47b725ae77Skettenis static int readchar (int timeout);
48b725ae77Skettenis 
49b725ae77Skettenis static void ocd_interrupt (int signo);
50b725ae77Skettenis 
51b725ae77Skettenis static void ocd_interrupt_twice (int signo);
52b725ae77Skettenis 
53b725ae77Skettenis static void interrupt_query (void);
54b725ae77Skettenis 
55b725ae77Skettenis static unsigned char *ocd_do_command (int cmd, int *statusp, int *lenp);
56b725ae77Skettenis 
57b725ae77Skettenis static void ocd_put_packet (unsigned char *packet, int pktlen);
58b725ae77Skettenis 
59b725ae77Skettenis static unsigned char *ocd_get_packet (int cmd, int *pktlen, int timeout);
60b725ae77Skettenis 
61b725ae77Skettenis static struct target_ops *current_ops = NULL;
62b725ae77Skettenis 
63b725ae77Skettenis static int last_run_status;
64b725ae77Skettenis 
65b725ae77Skettenis /* Descriptor for I/O to remote machine.  Initialize it to NULL so that
66b725ae77Skettenis    ocd_open knows that we don't have a file open when the program
67b725ae77Skettenis    starts.  */
68b725ae77Skettenis static struct serial *ocd_desc = NULL;
69b725ae77Skettenis 
70b725ae77Skettenis void
ocd_error(char * s,int error_code)71b725ae77Skettenis ocd_error (char *s, int error_code)
72b725ae77Skettenis {
73b725ae77Skettenis   char buf[100];
74b725ae77Skettenis 
75b725ae77Skettenis   fputs_filtered (s, gdb_stderr);
76b725ae77Skettenis   fputs_filtered (" ", gdb_stderr);
77b725ae77Skettenis 
78b725ae77Skettenis   switch (error_code)
79b725ae77Skettenis     {
80b725ae77Skettenis     case 0x1:
81b725ae77Skettenis       s = "Unknown fault";
82b725ae77Skettenis       break;
83b725ae77Skettenis     case 0x2:
84b725ae77Skettenis       s = "Power failed";
85b725ae77Skettenis       break;
86b725ae77Skettenis     case 0x3:
87b725ae77Skettenis       s = "Cable disconnected";
88b725ae77Skettenis       break;
89b725ae77Skettenis     case 0x4:
90b725ae77Skettenis       s = "Couldn't enter OCD mode";
91b725ae77Skettenis       break;
92b725ae77Skettenis     case 0x5:
93b725ae77Skettenis       s = "Target stuck in reset";
94b725ae77Skettenis       break;
95b725ae77Skettenis     case 0x6:
96b725ae77Skettenis       s = "OCD hasn't been initialized";
97b725ae77Skettenis       break;
98b725ae77Skettenis     case 0x7:
99b725ae77Skettenis       s = "Write verify failed";
100b725ae77Skettenis       break;
101b725ae77Skettenis     case 0x8:
102b725ae77Skettenis       s = "Reg buff error (during MPC5xx fp reg read/write)";
103b725ae77Skettenis       break;
104b725ae77Skettenis     case 0x9:
105b725ae77Skettenis       s = "Invalid CPU register access attempt failed";
106b725ae77Skettenis       break;
107b725ae77Skettenis     case 0x11:
108b725ae77Skettenis       s = "Bus error";
109b725ae77Skettenis       break;
110b725ae77Skettenis     case 0x12:
111b725ae77Skettenis       s = "Checksum error";
112b725ae77Skettenis       break;
113b725ae77Skettenis     case 0x13:
114b725ae77Skettenis       s = "Illegal command";
115b725ae77Skettenis       break;
116b725ae77Skettenis     case 0x14:
117b725ae77Skettenis       s = "Parameter error";
118b725ae77Skettenis       break;
119b725ae77Skettenis     case 0x15:
120b725ae77Skettenis       s = "Internal error";
121b725ae77Skettenis       break;
122b725ae77Skettenis     case 0x80:
123b725ae77Skettenis       s = "Flash erase error";
124b725ae77Skettenis       break;
125b725ae77Skettenis     default:
126b725ae77Skettenis       sprintf (buf, "Unknown error code %d", error_code);
127b725ae77Skettenis       s = buf;
128b725ae77Skettenis     }
129b725ae77Skettenis 
130b725ae77Skettenis   error ("%s", s);
131b725ae77Skettenis }
132b725ae77Skettenis 
133b725ae77Skettenis /*  Return nonzero if the thread TH is still alive on the remote system.  */
134b725ae77Skettenis 
135b725ae77Skettenis int
ocd_thread_alive(ptid_t th)136b725ae77Skettenis ocd_thread_alive (ptid_t th)
137b725ae77Skettenis {
138b725ae77Skettenis   return 1;
139b725ae77Skettenis }
140b725ae77Skettenis 
141b725ae77Skettenis /* Clean up connection to a remote debugger.  */
142b725ae77Skettenis 
143b725ae77Skettenis void
ocd_close(int quitting)144b725ae77Skettenis ocd_close (int quitting)
145b725ae77Skettenis {
146b725ae77Skettenis   if (ocd_desc)
147b725ae77Skettenis     serial_close (ocd_desc);
148b725ae77Skettenis   ocd_desc = NULL;
149b725ae77Skettenis }
150b725ae77Skettenis 
151b725ae77Skettenis /* Stub for catch_errors.  */
152b725ae77Skettenis 
153b725ae77Skettenis static int
ocd_start_remote(void * dummy)154b725ae77Skettenis ocd_start_remote (void *dummy)
155b725ae77Skettenis {
156b725ae77Skettenis   unsigned char buf[10], *p;
157b725ae77Skettenis   int pktlen;
158b725ae77Skettenis   int status;
159b725ae77Skettenis   int error_code;
160b725ae77Skettenis   int speed;
161b725ae77Skettenis   enum ocd_target_type target_type;
162b725ae77Skettenis 
163b725ae77Skettenis   target_type = *(enum ocd_target_type *) dummy;
164b725ae77Skettenis 
165b725ae77Skettenis   immediate_quit++;		/* Allow user to interrupt it */
166b725ae77Skettenis 
167b725ae77Skettenis   serial_send_break (ocd_desc);	/* Wake up the wiggler */
168b725ae77Skettenis 
169b725ae77Skettenis   speed = 80;			/* Divide clock by 4000 */
170b725ae77Skettenis 
171b725ae77Skettenis   buf[0] = OCD_INIT;
172b725ae77Skettenis   buf[1] = speed >> 8;
173b725ae77Skettenis   buf[2] = speed & 0xff;
174b725ae77Skettenis   buf[3] = target_type;
175b725ae77Skettenis   ocd_put_packet (buf, 4);	/* Init OCD params */
176b725ae77Skettenis   p = ocd_get_packet (buf[0], &pktlen, remote_timeout);
177b725ae77Skettenis 
178b725ae77Skettenis   if (pktlen < 2)
179b725ae77Skettenis     error ("Truncated response packet from OCD device");
180b725ae77Skettenis 
181b725ae77Skettenis   status = p[1];
182b725ae77Skettenis   error_code = p[2];
183b725ae77Skettenis 
184b725ae77Skettenis   if (error_code != 0)
185b725ae77Skettenis     ocd_error ("OCD_INIT:", error_code);
186b725ae77Skettenis 
187b725ae77Skettenis   ocd_do_command (OCD_AYT, &status, &pktlen);
188b725ae77Skettenis 
189b725ae77Skettenis   p = ocd_do_command (OCD_GET_VERSION, &status, &pktlen);
190b725ae77Skettenis 
191b725ae77Skettenis   printf_unfiltered ("[Wiggler version %x.%x, capability 0x%x]\n",
192b725ae77Skettenis 		     p[0], p[1], (p[2] << 16) | p[3]);
193b725ae77Skettenis 
194b725ae77Skettenis   /* If processor is still running, stop it.  */
195b725ae77Skettenis 
196b725ae77Skettenis   if (!(status & OCD_FLAG_BDM))
197b725ae77Skettenis     ocd_stop ();
198b725ae77Skettenis 
199b725ae77Skettenis   /* When using a target box, we want to asynchronously return status when
200b725ae77Skettenis      target stops.  The OCD_SET_CTL_FLAGS command is ignored by Wigglers.dll
201b725ae77Skettenis      when using a parallel Wiggler */
202b725ae77Skettenis   buf[0] = OCD_SET_CTL_FLAGS;
203b725ae77Skettenis   buf[1] = 0;
204b725ae77Skettenis   buf[2] = 1;
205b725ae77Skettenis   ocd_put_packet (buf, 3);
206b725ae77Skettenis 
207b725ae77Skettenis   p = ocd_get_packet (buf[0], &pktlen, remote_timeout);
208b725ae77Skettenis 
209b725ae77Skettenis   if (pktlen < 2)
210b725ae77Skettenis     error ("Truncated response packet from OCD device");
211b725ae77Skettenis 
212b725ae77Skettenis   status = p[1];
213b725ae77Skettenis   error_code = p[2];
214b725ae77Skettenis 
215b725ae77Skettenis   if (error_code != 0)
216b725ae77Skettenis     ocd_error ("OCD_SET_CTL_FLAGS:", error_code);
217b725ae77Skettenis 
218b725ae77Skettenis   immediate_quit--;
219b725ae77Skettenis 
220b725ae77Skettenis /* This is really the job of start_remote however, that makes an assumption
221b725ae77Skettenis    that the target is about to print out a status message of some sort.  That
222b725ae77Skettenis    doesn't happen here (in fact, it may not be possible to get the monitor to
223b725ae77Skettenis    send the appropriate packet).  */
224b725ae77Skettenis 
225b725ae77Skettenis   flush_cached_frames ();
226b725ae77Skettenis   registers_changed ();
227b725ae77Skettenis   stop_pc = read_pc ();
228*11efff7fSkettenis   print_stack_frame (get_selected_frame (), 0, SRC_AND_LOC);
229b725ae77Skettenis 
230b725ae77Skettenis   buf[0] = OCD_LOG_FILE;
231b725ae77Skettenis   buf[1] = 3;			/* close existing WIGGLERS.LOG */
232b725ae77Skettenis   ocd_put_packet (buf, 2);
233b725ae77Skettenis   p = ocd_get_packet (buf[0], &pktlen, remote_timeout);
234b725ae77Skettenis 
235b725ae77Skettenis   buf[0] = OCD_LOG_FILE;
236b725ae77Skettenis   buf[1] = 2;			/* append to existing WIGGLERS.LOG */
237b725ae77Skettenis   ocd_put_packet (buf, 2);
238b725ae77Skettenis   p = ocd_get_packet (buf[0], &pktlen, remote_timeout);
239b725ae77Skettenis 
240b725ae77Skettenis   return 1;
241b725ae77Skettenis }
242b725ae77Skettenis 
243b725ae77Skettenis /* Open a connection to a remote debugger.
244b725ae77Skettenis    NAME is the filename used for communication.  */
245b725ae77Skettenis 
246b725ae77Skettenis void
ocd_open(char * name,int from_tty,enum ocd_target_type target_type,struct target_ops * ops)247b725ae77Skettenis ocd_open (char *name, int from_tty, enum ocd_target_type target_type,
248b725ae77Skettenis 	  struct target_ops *ops)
249b725ae77Skettenis {
250b725ae77Skettenis   unsigned char buf[10], *p;
251b725ae77Skettenis   int pktlen;
252b725ae77Skettenis 
253b725ae77Skettenis   if (name == 0)
254b725ae77Skettenis     error ("To open an OCD connection, you need to specify the\n\
255b725ae77Skettenis device the OCD device is attached to (e.g. /dev/ttya).");
256b725ae77Skettenis 
257b725ae77Skettenis   target_preopen (from_tty);
258b725ae77Skettenis 
259b725ae77Skettenis   current_ops = ops;
260b725ae77Skettenis 
261b725ae77Skettenis   unpush_target (current_ops);
262b725ae77Skettenis 
263b725ae77Skettenis   ocd_desc = serial_open (name);
264b725ae77Skettenis   if (!ocd_desc)
265b725ae77Skettenis     perror_with_name (name);
266b725ae77Skettenis 
267b725ae77Skettenis   if (baud_rate != -1)
268b725ae77Skettenis     {
269b725ae77Skettenis       if (serial_setbaudrate (ocd_desc, baud_rate))
270b725ae77Skettenis 	{
271b725ae77Skettenis 	  serial_close (ocd_desc);
272b725ae77Skettenis 	  perror_with_name (name);
273b725ae77Skettenis 	}
274b725ae77Skettenis     }
275b725ae77Skettenis 
276b725ae77Skettenis   serial_raw (ocd_desc);
277b725ae77Skettenis 
278b725ae77Skettenis   /* If there is something sitting in the buffer we might take it as a
279b725ae77Skettenis      response to a command, which would be bad.  */
280b725ae77Skettenis   serial_flush_input (ocd_desc);
281b725ae77Skettenis 
282b725ae77Skettenis   if (from_tty)
283b725ae77Skettenis     {
284b725ae77Skettenis       puts_filtered ("Remote target wiggler connected to ");
285b725ae77Skettenis       puts_filtered (name);
286b725ae77Skettenis       puts_filtered ("\n");
287b725ae77Skettenis     }
288b725ae77Skettenis   push_target (current_ops);	/* Switch to using remote target now */
289b725ae77Skettenis 
290b725ae77Skettenis   /* Without this, some commands which require an active target (such as kill)
291b725ae77Skettenis      won't work.  This variable serves (at least) double duty as both the pid
292b725ae77Skettenis      of the target process (if it has such), and as a flag indicating that a
293b725ae77Skettenis      target is active.  These functions should be split out into seperate
294b725ae77Skettenis      variables, especially since GDB will someday have a notion of debugging
295b725ae77Skettenis      several processes.  */
296b725ae77Skettenis 
297b725ae77Skettenis   inferior_ptid = pid_to_ptid (42000);
298b725ae77Skettenis   /* Start the remote connection; if error (0), discard this target.
299b725ae77Skettenis      In particular, if the user quits, be sure to discard it
300b725ae77Skettenis      (we'd be in an inconsistent state otherwise).  */
301b725ae77Skettenis   if (!catch_errors (ocd_start_remote, &target_type,
302b725ae77Skettenis 		     "Couldn't establish connection to remote target\n",
303b725ae77Skettenis 		     RETURN_MASK_ALL))
304b725ae77Skettenis     {
305b725ae77Skettenis       pop_target ();
306b725ae77Skettenis       error ("Failed to connect to OCD.");
307b725ae77Skettenis     }
308b725ae77Skettenis }
309b725ae77Skettenis 
310b725ae77Skettenis /* This takes a program previously attached to and detaches it.  After
311b725ae77Skettenis    this is done, GDB can be used to debug some other program.  We
312b725ae77Skettenis    better not have left any breakpoints in the target program or it'll
313b725ae77Skettenis    die when it hits one.  */
314b725ae77Skettenis 
315b725ae77Skettenis void
ocd_detach(char * args,int from_tty)316b725ae77Skettenis ocd_detach (char *args, int from_tty)
317b725ae77Skettenis {
318b725ae77Skettenis   if (args)
319b725ae77Skettenis     error ("Argument given to \"detach\" when remotely debugging.");
320b725ae77Skettenis 
321b725ae77Skettenis   pop_target ();
322b725ae77Skettenis   if (from_tty)
323b725ae77Skettenis     puts_filtered ("Ending remote debugging.\n");
324b725ae77Skettenis }
325b725ae77Skettenis 
326b725ae77Skettenis /* Tell the remote machine to resume.  */
327b725ae77Skettenis 
328b725ae77Skettenis void
ocd_resume(ptid_t ptid,int step,enum target_signal siggnal)329b725ae77Skettenis ocd_resume (ptid_t ptid, int step, enum target_signal siggnal)
330b725ae77Skettenis {
331b725ae77Skettenis   int pktlen;
332b725ae77Skettenis 
333b725ae77Skettenis   if (step)
334b725ae77Skettenis     ocd_do_command (OCD_STEP, &last_run_status, &pktlen);
335b725ae77Skettenis   else
336b725ae77Skettenis     ocd_do_command (OCD_RUN, &last_run_status, &pktlen);
337b725ae77Skettenis }
338b725ae77Skettenis 
339b725ae77Skettenis void
ocd_stop(void)340b725ae77Skettenis ocd_stop (void)
341b725ae77Skettenis {
342b725ae77Skettenis   int status;
343b725ae77Skettenis   int pktlen;
344b725ae77Skettenis 
345b725ae77Skettenis   ocd_do_command (OCD_STOP, &status, &pktlen);
346b725ae77Skettenis 
347b725ae77Skettenis   if (!(status & OCD_FLAG_BDM))
348b725ae77Skettenis     error ("Can't stop target via BDM");
349b725ae77Skettenis }
350b725ae77Skettenis 
351b725ae77Skettenis static volatile int ocd_interrupt_flag;
352b725ae77Skettenis 
353b725ae77Skettenis /* Send ^C to target to halt it.  Target will respond, and send us a
354b725ae77Skettenis    packet.  */
355b725ae77Skettenis 
356b725ae77Skettenis static void
ocd_interrupt(int signo)357b725ae77Skettenis ocd_interrupt (int signo)
358b725ae77Skettenis {
359b725ae77Skettenis   /* If this doesn't work, try more severe steps.  */
360b725ae77Skettenis   signal (signo, ocd_interrupt_twice);
361b725ae77Skettenis 
362b725ae77Skettenis   if (remote_debug)
363b725ae77Skettenis     printf_unfiltered ("ocd_interrupt called\n");
364b725ae77Skettenis 
365b725ae77Skettenis   {
366b725ae77Skettenis     char buf[1];
367b725ae77Skettenis 
368b725ae77Skettenis     ocd_stop ();
369b725ae77Skettenis     buf[0] = OCD_AYT;
370b725ae77Skettenis     ocd_put_packet (buf, 1);
371b725ae77Skettenis     ocd_interrupt_flag = 1;
372b725ae77Skettenis   }
373b725ae77Skettenis }
374b725ae77Skettenis 
375b725ae77Skettenis static void (*ofunc) ();
376b725ae77Skettenis 
377b725ae77Skettenis /* The user typed ^C twice.  */
378b725ae77Skettenis static void
ocd_interrupt_twice(int signo)379b725ae77Skettenis ocd_interrupt_twice (int signo)
380b725ae77Skettenis {
381b725ae77Skettenis   signal (signo, ofunc);
382b725ae77Skettenis 
383b725ae77Skettenis   interrupt_query ();
384b725ae77Skettenis 
385b725ae77Skettenis   signal (signo, ocd_interrupt);
386b725ae77Skettenis }
387b725ae77Skettenis 
388b725ae77Skettenis /* Ask the user what to do when an interrupt is received.  */
389b725ae77Skettenis 
390b725ae77Skettenis static void
interrupt_query(void)391b725ae77Skettenis interrupt_query (void)
392b725ae77Skettenis {
393b725ae77Skettenis   target_terminal_ours ();
394b725ae77Skettenis 
395b725ae77Skettenis   if (query ("Interrupted while waiting for the program.\n\
396b725ae77Skettenis Give up (and stop debugging it)? "))
397b725ae77Skettenis     {
398b725ae77Skettenis       target_mourn_inferior ();
399b725ae77Skettenis       throw_exception (RETURN_QUIT);
400b725ae77Skettenis     }
401b725ae77Skettenis 
402b725ae77Skettenis   target_terminal_inferior ();
403b725ae77Skettenis }
404b725ae77Skettenis 
405b725ae77Skettenis /* If nonzero, ignore the next kill.  */
406b725ae77Skettenis static int kill_kludge;
407b725ae77Skettenis 
408b725ae77Skettenis /* Wait until the remote machine stops, then return,
409b725ae77Skettenis    storing status in STATUS just as `wait' would.
410b725ae77Skettenis    Returns "pid" (though it's not clear what, if anything, that
411b725ae77Skettenis    means in the case of this target).  */
412b725ae77Skettenis 
413b725ae77Skettenis int
ocd_wait(void)414b725ae77Skettenis ocd_wait (void)
415b725ae77Skettenis {
416b725ae77Skettenis   unsigned char *p;
417b725ae77Skettenis   int error_code;
418b725ae77Skettenis   int pktlen;
419b725ae77Skettenis   char buf[1];
420b725ae77Skettenis 
421b725ae77Skettenis   ocd_interrupt_flag = 0;
422b725ae77Skettenis 
423b725ae77Skettenis   /* Target might already be stopped by the time we get here. */
424b725ae77Skettenis   /* If we aren't already stopped, we need to loop until we've dropped
425b725ae77Skettenis      back into BDM mode */
426b725ae77Skettenis 
427b725ae77Skettenis   while (!(last_run_status & OCD_FLAG_BDM))
428b725ae77Skettenis     {
429b725ae77Skettenis       buf[0] = OCD_AYT;
430b725ae77Skettenis       ocd_put_packet (buf, 1);
431b725ae77Skettenis       p = ocd_get_packet (OCD_AYT, &pktlen, -1);
432b725ae77Skettenis 
433b725ae77Skettenis       ofunc = (void (*)()) signal (SIGINT, ocd_interrupt);
434b725ae77Skettenis       signal (SIGINT, ofunc);
435b725ae77Skettenis 
436b725ae77Skettenis       if (pktlen < 2)
437b725ae77Skettenis 	error ("Truncated response packet from OCD device");
438b725ae77Skettenis 
439b725ae77Skettenis       last_run_status = p[1];
440b725ae77Skettenis       error_code = p[2];
441b725ae77Skettenis 
442b725ae77Skettenis       if (error_code != 0)
443b725ae77Skettenis 	ocd_error ("target_wait:", error_code);
444b725ae77Skettenis 
445b725ae77Skettenis       if (last_run_status & OCD_FLAG_PWF)
446b725ae77Skettenis 	error ("OCD device lost VCC at BDM interface.");
447b725ae77Skettenis       else if (last_run_status & OCD_FLAG_CABLE_DISC)
448b725ae77Skettenis 	error ("OCD device cable appears to have been disconnected.");
449b725ae77Skettenis     }
450b725ae77Skettenis 
451b725ae77Skettenis   if (ocd_interrupt_flag)
452b725ae77Skettenis     return 1;
453b725ae77Skettenis   else
454b725ae77Skettenis     return 0;
455b725ae77Skettenis }
456b725ae77Skettenis 
457b725ae77Skettenis /* Read registers from the OCD device.  Specify the starting and ending
458b725ae77Skettenis    register number.  Return the number of regs actually read in *NUMREGS.
459b725ae77Skettenis    Returns a pointer to a static array containing the register contents.  */
460b725ae77Skettenis 
461b725ae77Skettenis unsigned char *
ocd_read_bdm_registers(int first_bdm_regno,int last_bdm_regno,int * reglen)462b725ae77Skettenis ocd_read_bdm_registers (int first_bdm_regno, int last_bdm_regno, int *reglen)
463b725ae77Skettenis {
464b725ae77Skettenis   unsigned char buf[10];
465b725ae77Skettenis   int i;
466b725ae77Skettenis   unsigned char *p;
467b725ae77Skettenis   unsigned char *regs;
468b725ae77Skettenis   int error_code, status;
469b725ae77Skettenis   int pktlen;
470b725ae77Skettenis 
471b725ae77Skettenis   buf[0] = OCD_READ_REGS;
472b725ae77Skettenis   buf[1] = first_bdm_regno >> 8;
473b725ae77Skettenis   buf[2] = first_bdm_regno & 0xff;
474b725ae77Skettenis   buf[3] = last_bdm_regno >> 8;
475b725ae77Skettenis   buf[4] = last_bdm_regno & 0xff;
476b725ae77Skettenis 
477b725ae77Skettenis   ocd_put_packet (buf, 5);
478b725ae77Skettenis   p = ocd_get_packet (OCD_READ_REGS, &pktlen, remote_timeout);
479b725ae77Skettenis 
480b725ae77Skettenis   status = p[1];
481b725ae77Skettenis   error_code = p[2];
482b725ae77Skettenis 
483b725ae77Skettenis   if (error_code != 0)
484b725ae77Skettenis     ocd_error ("read_bdm_registers:", error_code);
485b725ae77Skettenis 
486b725ae77Skettenis   i = p[3];
487b725ae77Skettenis   if (i == 0)
488b725ae77Skettenis     i = 256;
489b725ae77Skettenis 
490b725ae77Skettenis   if (i > pktlen - 4
491b725ae77Skettenis       || ((i & 3) != 0))
492b725ae77Skettenis     error ("Register block size bad:  %d", i);
493b725ae77Skettenis 
494b725ae77Skettenis   *reglen = i;
495b725ae77Skettenis 
496b725ae77Skettenis   regs = p + 4;
497b725ae77Skettenis 
498b725ae77Skettenis   return regs;
499b725ae77Skettenis }
500b725ae77Skettenis 
501b725ae77Skettenis /* Read register BDM_REGNO and returns its value ala read_register() */
502b725ae77Skettenis 
503b725ae77Skettenis CORE_ADDR
ocd_read_bdm_register(int bdm_regno)504b725ae77Skettenis ocd_read_bdm_register (int bdm_regno)
505b725ae77Skettenis {
506b725ae77Skettenis   int reglen;
507b725ae77Skettenis   unsigned char *p;
508b725ae77Skettenis   CORE_ADDR regval;
509b725ae77Skettenis 
510b725ae77Skettenis   p = ocd_read_bdm_registers (bdm_regno, bdm_regno, &reglen);
511b725ae77Skettenis   regval = extract_unsigned_integer (p, reglen);
512b725ae77Skettenis 
513b725ae77Skettenis   return regval;
514b725ae77Skettenis }
515b725ae77Skettenis 
516b725ae77Skettenis void
ocd_write_bdm_registers(int first_bdm_regno,unsigned char * regptr,int reglen)517b725ae77Skettenis ocd_write_bdm_registers (int first_bdm_regno, unsigned char *regptr, int reglen)
518b725ae77Skettenis {
519b725ae77Skettenis   unsigned char *buf;
520b725ae77Skettenis   unsigned char *p;
521b725ae77Skettenis   int error_code, status;
522b725ae77Skettenis   int pktlen;
523b725ae77Skettenis 
524b725ae77Skettenis   buf = alloca (4 + reglen);
525b725ae77Skettenis 
526b725ae77Skettenis   buf[0] = OCD_WRITE_REGS;
527b725ae77Skettenis   buf[1] = first_bdm_regno >> 8;
528b725ae77Skettenis   buf[2] = first_bdm_regno & 0xff;
529b725ae77Skettenis   buf[3] = reglen;
530b725ae77Skettenis   memcpy (buf + 4, regptr, reglen);
531b725ae77Skettenis 
532b725ae77Skettenis   ocd_put_packet (buf, 4 + reglen);
533b725ae77Skettenis   p = ocd_get_packet (OCD_WRITE_REGS, &pktlen, remote_timeout);
534b725ae77Skettenis 
535b725ae77Skettenis   if (pktlen < 3)
536b725ae77Skettenis     error ("Truncated response packet from OCD device");
537b725ae77Skettenis 
538b725ae77Skettenis   status = p[1];
539b725ae77Skettenis   error_code = p[2];
540b725ae77Skettenis 
541b725ae77Skettenis   if (error_code != 0)
542b725ae77Skettenis     ocd_error ("ocd_write_bdm_registers:", error_code);
543b725ae77Skettenis }
544b725ae77Skettenis 
545b725ae77Skettenis void
ocd_write_bdm_register(int bdm_regno,CORE_ADDR reg)546b725ae77Skettenis ocd_write_bdm_register (int bdm_regno, CORE_ADDR reg)
547b725ae77Skettenis {
548b725ae77Skettenis   unsigned char buf[4];
549b725ae77Skettenis 
550b725ae77Skettenis   store_unsigned_integer (buf, 4, reg);
551b725ae77Skettenis 
552b725ae77Skettenis   ocd_write_bdm_registers (bdm_regno, buf, 4);
553b725ae77Skettenis }
554b725ae77Skettenis 
555b725ae77Skettenis void
ocd_prepare_to_store(void)556b725ae77Skettenis ocd_prepare_to_store (void)
557b725ae77Skettenis {
558b725ae77Skettenis }
559b725ae77Skettenis 
560b725ae77Skettenis /* Write memory data directly to the remote machine.
561b725ae77Skettenis    This does not inform the data cache; the data cache uses this.
562b725ae77Skettenis    MEMADDR is the address in the remote memory space.
563b725ae77Skettenis    MYADDR is the address of the buffer in our space.
564b725ae77Skettenis    LEN is the number of bytes.
565b725ae77Skettenis 
566b725ae77Skettenis    Returns number of bytes transferred, or 0 for error.  */
567b725ae77Skettenis 
568b725ae77Skettenis static int write_mem_command = OCD_WRITE_MEM;
569b725ae77Skettenis 
570b725ae77Skettenis int
ocd_write_bytes(CORE_ADDR memaddr,char * myaddr,int len)571b725ae77Skettenis ocd_write_bytes (CORE_ADDR memaddr, char *myaddr, int len)
572b725ae77Skettenis {
573b725ae77Skettenis   char buf[256 + 10];
574b725ae77Skettenis   unsigned char *p;
575b725ae77Skettenis   int origlen;
576b725ae77Skettenis 
577b725ae77Skettenis   origlen = len;
578b725ae77Skettenis 
579b725ae77Skettenis   buf[0] = write_mem_command;
580b725ae77Skettenis   buf[5] = 1;			/* Write as bytes */
581b725ae77Skettenis   buf[6] = 0;			/* Don't verify */
582b725ae77Skettenis 
583b725ae77Skettenis   while (len > 0)
584b725ae77Skettenis     {
585b725ae77Skettenis       int numbytes;
586b725ae77Skettenis       int pktlen;
587b725ae77Skettenis       int status, error_code;
588b725ae77Skettenis 
589b725ae77Skettenis       numbytes = min (len, 256 - 8);
590b725ae77Skettenis 
591b725ae77Skettenis       buf[1] = memaddr >> 24;
592b725ae77Skettenis       buf[2] = memaddr >> 16;
593b725ae77Skettenis       buf[3] = memaddr >> 8;
594b725ae77Skettenis       buf[4] = memaddr;
595b725ae77Skettenis 
596b725ae77Skettenis       buf[7] = numbytes;
597b725ae77Skettenis 
598b725ae77Skettenis       memcpy (&buf[8], myaddr, numbytes);
599b725ae77Skettenis       ocd_put_packet (buf, 8 + numbytes);
600b725ae77Skettenis       p = ocd_get_packet (OCD_WRITE_MEM, &pktlen, remote_timeout);
601b725ae77Skettenis       if (pktlen < 3)
602b725ae77Skettenis 	error ("Truncated response packet from OCD device");
603b725ae77Skettenis 
604b725ae77Skettenis       status = p[1];
605b725ae77Skettenis       error_code = p[2];
606b725ae77Skettenis 
607b725ae77Skettenis       if (error_code == 0x11)	/* Got a bus error? */
608b725ae77Skettenis 	{
609b725ae77Skettenis 	  CORE_ADDR error_address;
610b725ae77Skettenis 
611b725ae77Skettenis 	  error_address = p[3] << 24;
612b725ae77Skettenis 	  error_address |= p[4] << 16;
613b725ae77Skettenis 	  error_address |= p[5] << 8;
614b725ae77Skettenis 	  error_address |= p[6];
615b725ae77Skettenis 	  numbytes = error_address - memaddr;
616b725ae77Skettenis 
617b725ae77Skettenis 	  len -= numbytes;
618b725ae77Skettenis 
619b725ae77Skettenis 	  errno = EIO;
620b725ae77Skettenis 
621b725ae77Skettenis 	  break;
622b725ae77Skettenis 	}
623b725ae77Skettenis       else if (error_code != 0)
624b725ae77Skettenis 	ocd_error ("ocd_write_bytes:", error_code);
625b725ae77Skettenis 
626b725ae77Skettenis       len -= numbytes;
627b725ae77Skettenis       memaddr += numbytes;
628b725ae77Skettenis       myaddr += numbytes;
629b725ae77Skettenis     }
630b725ae77Skettenis 
631b725ae77Skettenis   return origlen - len;
632b725ae77Skettenis }
633b725ae77Skettenis 
634b725ae77Skettenis /* Read memory data directly from the remote machine.
635b725ae77Skettenis    This does not use the data cache; the data cache uses this.
636b725ae77Skettenis    MEMADDR is the address in the remote memory space.
637b725ae77Skettenis    MYADDR is the address of the buffer in our space.
638b725ae77Skettenis    LEN is the number of bytes.
639b725ae77Skettenis 
640b725ae77Skettenis    Returns number of bytes transferred, or 0 for error.  */
641b725ae77Skettenis 
642b725ae77Skettenis static int
ocd_read_bytes(CORE_ADDR memaddr,char * myaddr,int len)643b725ae77Skettenis ocd_read_bytes (CORE_ADDR memaddr, char *myaddr, int len)
644b725ae77Skettenis {
645b725ae77Skettenis   char buf[256 + 10];
646b725ae77Skettenis   unsigned char *p;
647b725ae77Skettenis   int origlen;
648b725ae77Skettenis 
649b725ae77Skettenis   origlen = len;
650b725ae77Skettenis 
651b725ae77Skettenis   buf[0] = OCD_READ_MEM;
652b725ae77Skettenis   buf[5] = 1;			/* Read as bytes */
653b725ae77Skettenis 
654b725ae77Skettenis   while (len > 0)
655b725ae77Skettenis     {
656b725ae77Skettenis       int numbytes;
657b725ae77Skettenis       int pktlen;
658b725ae77Skettenis       int status, error_code;
659b725ae77Skettenis 
660b725ae77Skettenis       numbytes = min (len, 256 - 7);
661b725ae77Skettenis 
662b725ae77Skettenis       buf[1] = memaddr >> 24;
663b725ae77Skettenis       buf[2] = memaddr >> 16;
664b725ae77Skettenis       buf[3] = memaddr >> 8;
665b725ae77Skettenis       buf[4] = memaddr;
666b725ae77Skettenis 
667b725ae77Skettenis       buf[6] = numbytes;
668b725ae77Skettenis 
669b725ae77Skettenis       ocd_put_packet (buf, 7);
670b725ae77Skettenis       p = ocd_get_packet (OCD_READ_MEM, &pktlen, remote_timeout);
671b725ae77Skettenis       if (pktlen < 4)
672b725ae77Skettenis 	error ("Truncated response packet from OCD device");
673b725ae77Skettenis 
674b725ae77Skettenis       status = p[1];
675b725ae77Skettenis       error_code = p[2];
676b725ae77Skettenis 
677b725ae77Skettenis       if (error_code == 0x11)	/* Got a bus error? */
678b725ae77Skettenis 	{
679b725ae77Skettenis 	  CORE_ADDR error_address;
680b725ae77Skettenis 
681b725ae77Skettenis 	  error_address = p[3] << 24;
682b725ae77Skettenis 	  error_address |= p[4] << 16;
683b725ae77Skettenis 	  error_address |= p[5] << 8;
684b725ae77Skettenis 	  error_address |= p[6];
685b725ae77Skettenis 	  numbytes = error_address - memaddr;
686b725ae77Skettenis 
687b725ae77Skettenis 	  len -= numbytes;
688b725ae77Skettenis 
689b725ae77Skettenis 	  errno = EIO;
690b725ae77Skettenis 
691b725ae77Skettenis 	  break;
692b725ae77Skettenis 	}
693b725ae77Skettenis       else if (error_code != 0)
694b725ae77Skettenis 	ocd_error ("ocd_read_bytes:", error_code);
695b725ae77Skettenis 
696b725ae77Skettenis       memcpy (myaddr, &p[4], numbytes);
697b725ae77Skettenis 
698b725ae77Skettenis       len -= numbytes;
699b725ae77Skettenis       memaddr += numbytes;
700b725ae77Skettenis       myaddr += numbytes;
701b725ae77Skettenis     }
702b725ae77Skettenis 
703b725ae77Skettenis   return origlen - len;
704b725ae77Skettenis }
705b725ae77Skettenis 
706b725ae77Skettenis /* Read or write LEN bytes from inferior memory at MEMADDR, transferring
707b725ae77Skettenis    to or from debugger address MYADDR.  Write to inferior if SHOULD_WRITE is
708b725ae77Skettenis    nonzero.  Returns length of data written or read; 0 for error.  TARGET
709b725ae77Skettenis    is ignored.  */
710b725ae77Skettenis 
711b725ae77Skettenis int
ocd_xfer_memory(CORE_ADDR memaddr,char * myaddr,int len,int should_write,struct mem_attrib * attrib,struct target_ops * target)712b725ae77Skettenis ocd_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int should_write,
713b725ae77Skettenis 		 struct mem_attrib *attrib, struct target_ops *target)
714b725ae77Skettenis {
715b725ae77Skettenis   int res;
716b725ae77Skettenis 
717b725ae77Skettenis   if (should_write)
718b725ae77Skettenis     res = ocd_write_bytes (memaddr, myaddr, len);
719b725ae77Skettenis   else
720b725ae77Skettenis     res = ocd_read_bytes (memaddr, myaddr, len);
721b725ae77Skettenis 
722b725ae77Skettenis   return res;
723b725ae77Skettenis }
724b725ae77Skettenis 
725b725ae77Skettenis void
ocd_files_info(struct target_ops * ignore)726b725ae77Skettenis ocd_files_info (struct target_ops *ignore)
727b725ae77Skettenis {
728b725ae77Skettenis   puts_filtered ("Debugging a target over a serial line.\n");
729b725ae77Skettenis }
730b725ae77Skettenis 
731b725ae77Skettenis /* Stuff for dealing with the packets which are part of this protocol.
732b725ae77Skettenis    See comment at top of file for details.  */
733b725ae77Skettenis 
734b725ae77Skettenis /* Read a single character from the remote side, handling wierd errors. */
735b725ae77Skettenis 
736b725ae77Skettenis static int
readchar(int timeout)737b725ae77Skettenis readchar (int timeout)
738b725ae77Skettenis {
739b725ae77Skettenis   int ch;
740b725ae77Skettenis 
741b725ae77Skettenis   ch = serial_readchar (ocd_desc, timeout);
742b725ae77Skettenis 
743b725ae77Skettenis   switch (ch)
744b725ae77Skettenis     {
745b725ae77Skettenis     case SERIAL_EOF:
746b725ae77Skettenis       error ("Remote connection closed");
747b725ae77Skettenis     case SERIAL_ERROR:
748b725ae77Skettenis       perror_with_name ("Remote communication error");
749b725ae77Skettenis     case SERIAL_TIMEOUT:
750b725ae77Skettenis     default:
751b725ae77Skettenis       return ch;
752b725ae77Skettenis     }
753b725ae77Skettenis }
754b725ae77Skettenis 
755b725ae77Skettenis /* Send a packet to the OCD device.  The packet framed by a SYN character,
756b725ae77Skettenis    a byte count and a checksum.  The byte count only counts the number of
757b725ae77Skettenis    bytes between the count and the checksum.  A count of zero actually
758b725ae77Skettenis    means 256.  Any SYNs within the packet (including the checksum and
759b725ae77Skettenis    count) must be quoted.  The quote character must be quoted as well.
760b725ae77Skettenis    Quoting is done by replacing the character with the two-character sequence
761b725ae77Skettenis    DLE, {char} | 0100.  Note that the quoting mechanism has no effect on the
762b725ae77Skettenis    byte count.  */
763b725ae77Skettenis 
764b725ae77Skettenis static void
ocd_put_packet(unsigned char * buf,int len)765b725ae77Skettenis ocd_put_packet (unsigned char *buf, int len)
766b725ae77Skettenis {
767b725ae77Skettenis   unsigned char checksum;
768b725ae77Skettenis   unsigned char c;
769b725ae77Skettenis   unsigned char *packet, *packet_ptr;
770b725ae77Skettenis 
771b725ae77Skettenis   packet = alloca (len + 1 + 1);	/* packet + SYN + checksum */
772b725ae77Skettenis   packet_ptr = packet;
773b725ae77Skettenis 
774b725ae77Skettenis   checksum = 0;
775b725ae77Skettenis 
776b725ae77Skettenis   *packet_ptr++ = 0x55;
777b725ae77Skettenis 
778b725ae77Skettenis   while (len-- > 0)
779b725ae77Skettenis     {
780b725ae77Skettenis       c = *buf++;
781b725ae77Skettenis 
782b725ae77Skettenis       checksum += c;
783b725ae77Skettenis       *packet_ptr++ = c;
784b725ae77Skettenis     }
785b725ae77Skettenis 
786b725ae77Skettenis   *packet_ptr++ = -checksum;
787b725ae77Skettenis   if (serial_write (ocd_desc, packet, packet_ptr - packet))
788b725ae77Skettenis     perror_with_name ("output_packet: write failed");
789b725ae77Skettenis }
790b725ae77Skettenis 
791b725ae77Skettenis /* Get a packet from the OCD device.  Timeout is only enforced for the
792b725ae77Skettenis    first byte of the packet.  Subsequent bytes are expected to arrive in
793b725ae77Skettenis    time <= remote_timeout.  Returns a pointer to a static buffer containing
794b725ae77Skettenis    the payload of the packet.  *LENP contains the length of the packet.
795b725ae77Skettenis  */
796b725ae77Skettenis 
797b725ae77Skettenis static unsigned char *
ocd_get_packet(int cmd,int * lenp,int timeout)798b725ae77Skettenis ocd_get_packet (int cmd, int *lenp, int timeout)
799b725ae77Skettenis {
800b725ae77Skettenis   int ch;
801b725ae77Skettenis   int len;
802b725ae77Skettenis   static unsigned char packet[512];
803b725ae77Skettenis   unsigned char *packet_ptr;
804b725ae77Skettenis   unsigned char checksum;
805b725ae77Skettenis 
806b725ae77Skettenis   ch = readchar (timeout);
807b725ae77Skettenis 
808b725ae77Skettenis   if (ch < 0)
809b725ae77Skettenis     error ("ocd_get_packet (readchar): %d", ch);
810b725ae77Skettenis 
811b725ae77Skettenis   if (ch != 0x55)
812b725ae77Skettenis     error ("ocd_get_packet (readchar): %d", ch);
813b725ae77Skettenis 
814b725ae77Skettenis /* Found the start of a packet */
815b725ae77Skettenis 
816b725ae77Skettenis   packet_ptr = packet;
817b725ae77Skettenis   checksum = 0;
818b725ae77Skettenis 
819b725ae77Skettenis /* Read command char.  That sort of tells us how long the packet is. */
820b725ae77Skettenis 
821b725ae77Skettenis   ch = readchar (timeout);
822b725ae77Skettenis 
823b725ae77Skettenis   if (ch < 0)
824b725ae77Skettenis     error ("ocd_get_packet (readchar): %d", ch);
825b725ae77Skettenis 
826b725ae77Skettenis   *packet_ptr++ = ch;
827b725ae77Skettenis   checksum += ch;
828b725ae77Skettenis 
829b725ae77Skettenis /* Get status. */
830b725ae77Skettenis 
831b725ae77Skettenis   ch = readchar (timeout);
832b725ae77Skettenis 
833b725ae77Skettenis   if (ch < 0)
834b725ae77Skettenis     error ("ocd_get_packet (readchar): %d", ch);
835b725ae77Skettenis   *packet_ptr++ = ch;
836b725ae77Skettenis   checksum += ch;
837b725ae77Skettenis 
838b725ae77Skettenis /* Get error code. */
839b725ae77Skettenis 
840b725ae77Skettenis   ch = readchar (timeout);
841b725ae77Skettenis 
842b725ae77Skettenis   if (ch < 0)
843b725ae77Skettenis     error ("ocd_get_packet (readchar): %d", ch);
844b725ae77Skettenis   *packet_ptr++ = ch;
845b725ae77Skettenis   checksum += ch;
846b725ae77Skettenis 
847b725ae77Skettenis   switch (ch)			/* Figure out length of packet */
848b725ae77Skettenis     {
849b725ae77Skettenis     case 0x7:			/* Write verify error? */
850b725ae77Skettenis       len = 8;			/* write address, value read back */
851b725ae77Skettenis       break;
852b725ae77Skettenis     case 0x11:			/* Bus error? */
853b725ae77Skettenis       /* write address, read flag */
854b725ae77Skettenis     case 0x15:			/* Internal error */
855b725ae77Skettenis       len = 5;			/* error code, vector */
856b725ae77Skettenis       break;
857b725ae77Skettenis     default:			/* Error w/no params */
858b725ae77Skettenis       len = 0;
859b725ae77Skettenis       break;
860b725ae77Skettenis     case 0x0:			/* Normal result */
861b725ae77Skettenis       switch (packet[0])
862b725ae77Skettenis 	{
863b725ae77Skettenis 	case OCD_AYT:		/* Are You There? */
864b725ae77Skettenis 	case OCD_SET_BAUD_RATE:	/* Set Baud Rate */
865b725ae77Skettenis 	case OCD_INIT:		/* Initialize OCD device */
866b725ae77Skettenis 	case OCD_SET_SPEED:	/* Set Speed */
867b725ae77Skettenis 	case OCD_SET_FUNC_CODE:	/* Set Function Code */
868b725ae77Skettenis 	case OCD_SET_CTL_FLAGS:	/* Set Control Flags */
869b725ae77Skettenis 	case OCD_SET_BUF_ADDR:	/* Set Register Buffer Address */
870b725ae77Skettenis 	case OCD_RUN:		/* Run Target from PC  */
871b725ae77Skettenis 	case OCD_RUN_ADDR:	/* Run Target from Specified Address  */
872b725ae77Skettenis 	case OCD_STOP:		/* Stop Target */
873b725ae77Skettenis 	case OCD_RESET_RUN:	/* Reset Target and Run */
874b725ae77Skettenis 	case OCD_RESET:	/* Reset Target and Halt */
875b725ae77Skettenis 	case OCD_STEP:		/* Single Step */
876b725ae77Skettenis 	case OCD_WRITE_REGS:	/* Write Register */
877b725ae77Skettenis 	case OCD_WRITE_MEM:	/* Write Memory */
878b725ae77Skettenis 	case OCD_FILL_MEM:	/* Fill Memory */
879b725ae77Skettenis 	case OCD_MOVE_MEM:	/* Move Memory */
880b725ae77Skettenis 	case OCD_WRITE_INT_MEM:	/* Write Internal Memory */
881b725ae77Skettenis 	case OCD_JUMP:		/* Jump to Subroutine */
882b725ae77Skettenis 	case OCD_ERASE_FLASH:	/* Erase flash memory */
883b725ae77Skettenis 	case OCD_PROGRAM_FLASH:	/* Write flash memory */
884b725ae77Skettenis 	case OCD_EXIT_MON:	/* Exit the flash programming monitor  */
885b725ae77Skettenis 	case OCD_ENTER_MON:	/* Enter the flash programming monitor  */
886b725ae77Skettenis 	case OCD_LOG_FILE:	/* Make Wigglers.dll save Wigglers.log */
887b725ae77Skettenis 	case OCD_SET_CONNECTION:	/* Set type of connection in Wigglers.dll */
888b725ae77Skettenis 	  len = 0;
889b725ae77Skettenis 	  break;
890b725ae77Skettenis 	case OCD_GET_VERSION:	/* Get Version */
891b725ae77Skettenis 	  len = 10;
892b725ae77Skettenis 	  break;
893b725ae77Skettenis 	case OCD_GET_STATUS_MASK:	/* Get Status Mask */
894b725ae77Skettenis 	  len = 1;
895b725ae77Skettenis 	  break;
896b725ae77Skettenis 	case OCD_GET_CTRS:	/* Get Error Counters */
897b725ae77Skettenis 	case OCD_READ_REGS:	/* Read Register */
898b725ae77Skettenis 	case OCD_READ_MEM:	/* Read Memory */
899b725ae77Skettenis 	case OCD_READ_INT_MEM:	/* Read Internal Memory */
900b725ae77Skettenis 	  len = 257;
901b725ae77Skettenis 	  break;
902b725ae77Skettenis 	default:
903b725ae77Skettenis 	  error ("ocd_get_packet: unknown packet type 0x%x\n", ch);
904b725ae77Skettenis 	}
905b725ae77Skettenis     }
906b725ae77Skettenis 
907b725ae77Skettenis   if (len == 257)		/* Byte stream? */
908b725ae77Skettenis     {				/* Yes, byte streams contain the length */
909b725ae77Skettenis       ch = readchar (timeout);
910b725ae77Skettenis 
911b725ae77Skettenis       if (ch < 0)
912b725ae77Skettenis 	error ("ocd_get_packet (readchar): %d", ch);
913b725ae77Skettenis       *packet_ptr++ = ch;
914b725ae77Skettenis       checksum += ch;
915b725ae77Skettenis       len = ch;
916b725ae77Skettenis       if (len == 0)
917b725ae77Skettenis 	len = 256;
918b725ae77Skettenis     }
919b725ae77Skettenis 
920b725ae77Skettenis   while (len-- >= 0)		/* Do rest of packet and checksum */
921b725ae77Skettenis     {
922b725ae77Skettenis       ch = readchar (timeout);
923b725ae77Skettenis 
924b725ae77Skettenis       if (ch < 0)
925b725ae77Skettenis 	error ("ocd_get_packet (readchar): %d", ch);
926b725ae77Skettenis       *packet_ptr++ = ch;
927b725ae77Skettenis       checksum += ch;
928b725ae77Skettenis     }
929b725ae77Skettenis 
930b725ae77Skettenis   if (checksum != 0)
931b725ae77Skettenis     error ("ocd_get_packet: bad packet checksum");
932b725ae77Skettenis 
933b725ae77Skettenis   if (cmd != -1 && cmd != packet[0])
934b725ae77Skettenis     error ("Response phase error.  Got 0x%x, expected 0x%x", packet[0], cmd);
935b725ae77Skettenis 
936b725ae77Skettenis   *lenp = packet_ptr - packet - 1;	/* Subtract checksum byte */
937b725ae77Skettenis   return packet;
938b725ae77Skettenis }
939b725ae77Skettenis 
940b725ae77Skettenis /* Execute a simple (one-byte) command.  Returns a pointer to the data
941b725ae77Skettenis    following the error code.  */
942b725ae77Skettenis 
943b725ae77Skettenis static unsigned char *
ocd_do_command(int cmd,int * statusp,int * lenp)944b725ae77Skettenis ocd_do_command (int cmd, int *statusp, int *lenp)
945b725ae77Skettenis {
946b725ae77Skettenis   unsigned char buf[100], *p;
947b725ae77Skettenis   int status, error_code;
948b725ae77Skettenis   char errbuf[100];
949b725ae77Skettenis 
950b725ae77Skettenis   unsigned char logbuf[100];
951b725ae77Skettenis   int logpktlen;
952b725ae77Skettenis 
953b725ae77Skettenis   buf[0] = cmd;
954b725ae77Skettenis   ocd_put_packet (buf, 1);	/* Send command */
955b725ae77Skettenis   p = ocd_get_packet (*buf, lenp, remote_timeout);
956b725ae77Skettenis 
957b725ae77Skettenis   if (*lenp < 3)
958b725ae77Skettenis     error ("Truncated response packet from OCD device");
959b725ae77Skettenis 
960b725ae77Skettenis   status = p[1];
961b725ae77Skettenis   error_code = p[2];
962b725ae77Skettenis 
963b725ae77Skettenis   if (error_code != 0)
964b725ae77Skettenis     {
965b725ae77Skettenis       sprintf (errbuf, "ocd_do_command (0x%x):", cmd);
966b725ae77Skettenis       ocd_error (errbuf, error_code);
967b725ae77Skettenis     }
968b725ae77Skettenis 
969b725ae77Skettenis   if (status & OCD_FLAG_PWF)
970b725ae77Skettenis     error ("OCD device can't detect VCC at BDM interface.");
971b725ae77Skettenis   else if (status & OCD_FLAG_CABLE_DISC)
972b725ae77Skettenis     error ("BDM cable appears to be disconnected.");
973b725ae77Skettenis 
974b725ae77Skettenis   *statusp = status;
975b725ae77Skettenis 
976b725ae77Skettenis   logbuf[0] = OCD_LOG_FILE;
977b725ae77Skettenis   logbuf[1] = 3;		/* close existing WIGGLERS.LOG */
978b725ae77Skettenis   ocd_put_packet (logbuf, 2);
979b725ae77Skettenis   ocd_get_packet (logbuf[0], &logpktlen, remote_timeout);
980b725ae77Skettenis 
981b725ae77Skettenis   logbuf[0] = OCD_LOG_FILE;
982b725ae77Skettenis   logbuf[1] = 2;		/* append to existing WIGGLERS.LOG */
983b725ae77Skettenis   ocd_put_packet (logbuf, 2);
984b725ae77Skettenis   ocd_get_packet (logbuf[0], &logpktlen, remote_timeout);
985b725ae77Skettenis 
986b725ae77Skettenis   return p + 3;
987b725ae77Skettenis }
988b725ae77Skettenis 
989b725ae77Skettenis void
ocd_kill(void)990b725ae77Skettenis ocd_kill (void)
991b725ae77Skettenis {
992b725ae77Skettenis   /* For some mysterious reason, wait_for_inferior calls kill instead of
993b725ae77Skettenis      mourn after it gets TARGET_WAITKIND_SIGNALLED.  Work around it.  */
994b725ae77Skettenis   if (kill_kludge)
995b725ae77Skettenis     {
996b725ae77Skettenis       kill_kludge = 0;
997b725ae77Skettenis       target_mourn_inferior ();
998b725ae77Skettenis       return;
999b725ae77Skettenis     }
1000b725ae77Skettenis 
1001b725ae77Skettenis   /* Don't wait for it to die.  I'm not really sure it matters whether
1002b725ae77Skettenis      we do or not.  */
1003b725ae77Skettenis   target_mourn_inferior ();
1004b725ae77Skettenis }
1005b725ae77Skettenis 
1006b725ae77Skettenis void
ocd_mourn(void)1007b725ae77Skettenis ocd_mourn (void)
1008b725ae77Skettenis {
1009b725ae77Skettenis   unpush_target (current_ops);
1010b725ae77Skettenis   generic_mourn_inferior ();
1011b725ae77Skettenis }
1012b725ae77Skettenis 
1013b725ae77Skettenis /* All we actually do is set the PC to the start address of exec_bfd, and start
1014b725ae77Skettenis    the program at that point.  */
1015b725ae77Skettenis 
1016b725ae77Skettenis void
ocd_create_inferior(char * exec_file,char * args,char ** env,int from_tty)1017*11efff7fSkettenis ocd_create_inferior (char *exec_file, char *args, char **env, int from_tty)
1018b725ae77Skettenis {
1019b725ae77Skettenis   if (args && (*args != '\000'))
1020b725ae77Skettenis     error ("Args are not supported by BDM.");
1021b725ae77Skettenis 
1022b725ae77Skettenis   clear_proceed_status ();
1023b725ae77Skettenis   proceed (bfd_get_start_address (exec_bfd), TARGET_SIGNAL_0, 0);
1024b725ae77Skettenis }
1025b725ae77Skettenis 
1026b725ae77Skettenis void
ocd_load(char * args,int from_tty)1027b725ae77Skettenis ocd_load (char *args, int from_tty)
1028b725ae77Skettenis {
1029b725ae77Skettenis   generic_load (args, from_tty);
1030b725ae77Skettenis 
1031b725ae77Skettenis   inferior_ptid = null_ptid;
1032b725ae77Skettenis 
1033b725ae77Skettenis /* This is necessary because many things were based on the PC at the time that
1034b725ae77Skettenis    we attached to the monitor, which is no longer valid now that we have loaded
1035b725ae77Skettenis    new code (and just changed the PC).  Another way to do this might be to call
1036b725ae77Skettenis    normal_stop, except that the stack may not be valid, and things would get
1037b725ae77Skettenis    horribly confused... */
1038b725ae77Skettenis 
1039b725ae77Skettenis   clear_symtab_users ();
1040b725ae77Skettenis }
1041b725ae77Skettenis 
1042b725ae77Skettenis /* This should be defined for each target */
1043b725ae77Skettenis /* But we want to be able to compile this file for some configurations
1044b725ae77Skettenis    not yet supported fully */
1045b725ae77Skettenis 
1046b725ae77Skettenis #define BDM_BREAKPOINT {0x0,0x0,0x0,0x0}	/* For ppc 8xx */
1047b725ae77Skettenis 
1048b725ae77Skettenis /* BDM (at least on CPU32) uses a different breakpoint */
1049b725ae77Skettenis 
1050b725ae77Skettenis int
ocd_insert_breakpoint(CORE_ADDR addr,char * contents_cache)1051b725ae77Skettenis ocd_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
1052b725ae77Skettenis {
1053b725ae77Skettenis   static char break_insn[] = BDM_BREAKPOINT;
1054b725ae77Skettenis   int val;
1055b725ae77Skettenis 
1056b725ae77Skettenis   val = target_read_memory (addr, contents_cache, sizeof (break_insn));
1057b725ae77Skettenis 
1058b725ae77Skettenis   if (val == 0)
1059b725ae77Skettenis     val = target_write_memory (addr, break_insn, sizeof (break_insn));
1060b725ae77Skettenis 
1061b725ae77Skettenis   return val;
1062b725ae77Skettenis }
1063b725ae77Skettenis 
1064b725ae77Skettenis int
ocd_remove_breakpoint(CORE_ADDR addr,char * contents_cache)1065b725ae77Skettenis ocd_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
1066b725ae77Skettenis {
1067b725ae77Skettenis   static char break_insn[] = BDM_BREAKPOINT;
1068b725ae77Skettenis   int val;
1069b725ae77Skettenis 
1070b725ae77Skettenis   val = target_write_memory (addr, contents_cache, sizeof (break_insn));
1071b725ae77Skettenis 
1072b725ae77Skettenis   return val;
1073b725ae77Skettenis }
1074b725ae77Skettenis 
1075b725ae77Skettenis static void
bdm_command(char * args,int from_tty)1076b725ae77Skettenis bdm_command (char *args, int from_tty)
1077b725ae77Skettenis {
1078b725ae77Skettenis   error ("bdm command must be followed by `reset'");
1079b725ae77Skettenis }
1080b725ae77Skettenis 
1081b725ae77Skettenis static void
bdm_reset_command(char * args,int from_tty)1082b725ae77Skettenis bdm_reset_command (char *args, int from_tty)
1083b725ae77Skettenis {
1084b725ae77Skettenis   int status, pktlen;
1085b725ae77Skettenis 
1086b725ae77Skettenis   if (!ocd_desc)
1087b725ae77Skettenis     error ("Not connected to OCD device.");
1088b725ae77Skettenis 
1089b725ae77Skettenis   ocd_do_command (OCD_RESET, &status, &pktlen);
1090b725ae77Skettenis   dcache_invalidate (target_dcache);
1091b725ae77Skettenis   registers_changed ();
1092b725ae77Skettenis }
1093b725ae77Skettenis 
1094b725ae77Skettenis static void
bdm_restart_command(char * args,int from_tty)1095b725ae77Skettenis bdm_restart_command (char *args, int from_tty)
1096b725ae77Skettenis {
1097b725ae77Skettenis   int status, pktlen;
1098b725ae77Skettenis 
1099b725ae77Skettenis   if (!ocd_desc)
1100b725ae77Skettenis     error ("Not connected to OCD device.");
1101b725ae77Skettenis 
1102b725ae77Skettenis   ocd_do_command (OCD_RESET_RUN, &status, &pktlen);
1103b725ae77Skettenis   last_run_status = status;
1104b725ae77Skettenis   clear_proceed_status ();
1105b725ae77Skettenis   wait_for_inferior ();
1106b725ae77Skettenis   normal_stop ();
1107b725ae77Skettenis }
1108b725ae77Skettenis 
1109b725ae77Skettenis /* Temporary replacement for target_store_registers().  This prevents
1110b725ae77Skettenis    generic_load from trying to set the PC.  */
1111b725ae77Skettenis 
1112b725ae77Skettenis static void
noop_store_registers(int regno)1113b725ae77Skettenis noop_store_registers (int regno)
1114b725ae77Skettenis {
1115b725ae77Skettenis }
1116b725ae77Skettenis 
1117b725ae77Skettenis static void
bdm_update_flash_command(char * args,int from_tty)1118b725ae77Skettenis bdm_update_flash_command (char *args, int from_tty)
1119b725ae77Skettenis {
1120b725ae77Skettenis   int status, pktlen;
1121b725ae77Skettenis   struct cleanup *old_chain;
1122b725ae77Skettenis   void (*store_registers_tmp) (int);
1123b725ae77Skettenis 
1124b725ae77Skettenis   if (!ocd_desc)
1125b725ae77Skettenis     error ("Not connected to OCD device.");
1126b725ae77Skettenis 
1127b725ae77Skettenis   if (!args)
1128b725ae77Skettenis     error ("Must specify file containing new OCD code.");
1129b725ae77Skettenis 
1130b725ae77Skettenis /*  old_chain = make_cleanup (flash_cleanup, 0); */
1131b725ae77Skettenis 
1132b725ae77Skettenis   ocd_do_command (OCD_ENTER_MON, &status, &pktlen);
1133b725ae77Skettenis 
1134b725ae77Skettenis   ocd_do_command (OCD_ERASE_FLASH, &status, &pktlen);
1135b725ae77Skettenis 
1136b725ae77Skettenis   write_mem_command = OCD_PROGRAM_FLASH;
1137b725ae77Skettenis   store_registers_tmp = current_target.to_store_registers;
1138b725ae77Skettenis   current_target.to_store_registers = noop_store_registers;
1139b725ae77Skettenis 
1140b725ae77Skettenis   generic_load (args, from_tty);
1141b725ae77Skettenis 
1142b725ae77Skettenis   current_target.to_store_registers = store_registers_tmp;
1143b725ae77Skettenis   write_mem_command = OCD_WRITE_MEM;
1144b725ae77Skettenis 
1145b725ae77Skettenis   ocd_do_command (OCD_EXIT_MON, &status, &pktlen);
1146b725ae77Skettenis 
1147b725ae77Skettenis /*  discard_cleanups (old_chain); */
1148b725ae77Skettenis }
1149b725ae77Skettenis 
1150b725ae77Skettenis extern initialize_file_ftype _initialize_remote_ocd; /* -Wmissing-prototypes */
1151b725ae77Skettenis 
1152b725ae77Skettenis void
_initialize_remote_ocd(void)1153b725ae77Skettenis _initialize_remote_ocd (void)
1154b725ae77Skettenis {
1155b725ae77Skettenis   extern struct cmd_list_element *cmdlist;
1156b725ae77Skettenis   static struct cmd_list_element *ocd_cmd_list = NULL;
1157b725ae77Skettenis 
1158*11efff7fSkettenis   deprecated_add_show_from_set
1159*11efff7fSkettenis     (add_set_cmd ("remotetimeout", no_class,
1160b725ae77Skettenis 		  var_integer, (char *) &remote_timeout,
1161b725ae77Skettenis 		  "Set timeout value for remote read.\n", &setlist),
1162b725ae77Skettenis      &showlist);
1163b725ae77Skettenis 
1164b725ae77Skettenis   add_prefix_cmd ("ocd", class_obscure, bdm_command, "", &ocd_cmd_list, "ocd ",
1165b725ae77Skettenis 		  0, &cmdlist);
1166b725ae77Skettenis 
1167b725ae77Skettenis   add_cmd ("reset", class_obscure, bdm_reset_command, "", &ocd_cmd_list);
1168b725ae77Skettenis   add_cmd ("restart", class_obscure, bdm_restart_command, "", &ocd_cmd_list);
1169b725ae77Skettenis   add_cmd ("update-flash", class_obscure, bdm_update_flash_command, "", &ocd_cmd_list);
1170b725ae77Skettenis }
1171