break dcache out of remote-nindy.c
[platform/upstream/binutils.git] / gdb / remote-nindy.c
1 /* Memory-access and commands for remote NINDY process, for GDB.
2    Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
3    Contributed by Intel Corporation.  Modified from remote.c by Chris Benenati.
4
5 GDB is distributed in the hope that it will be useful, but WITHOUT ANY
6 WARRANTY.  No author or distributor accepts responsibility to anyone
7 for the consequences of using it or for whether it serves any
8 particular purpose or works at all, unless he says so in writing.
9 Refer to the GDB General Public License for full details.
10
11 Everyone is granted permission to copy, modify and redistribute GDB,
12 but only under the conditions described in the GDB General Public
13 License.  A copy of this license is supposed to have been given to you
14 along with GDB so you can know your rights and responsibilities.  It
15 should be in a file named COPYING.  Among other things, the copyright
16 notice and this notice must be preserved on all copies.
17
18 In other words, go ahead and share GDB, but don't try to stop
19 anyone else from sharing it farther.  Help stamp out software hoarding!
20 */
21
22 /*
23 Except for the data cache routines, this file bears little resemblence
24 to remote.c.  A new (although similar) protocol has been specified, and
25 portions of the code are entirely dependent on having an i80960 with a
26 NINDY ROM monitor at the other end of the line.
27 */
28
29 /*****************************************************************************
30  *
31  * REMOTE COMMUNICATION PROTOCOL BETWEEN GDB960 AND THE NINDY ROM MONITOR.
32  *
33  *
34  * MODES OF OPERATION
35  * ----- -- ---------
36  *      
37  * As far as NINDY is concerned, GDB is always in one of two modes: command
38  * mode or passthrough mode.
39  *
40  * In command mode (the default) pre-defined packets containing requests
41  * are sent by GDB to NINDY.  NINDY never talks except in reponse to a request.
42  *
43  * Once the the user program is started, GDB enters passthrough mode, to give
44  * the user program access to the terminal.  GDB remains in this mode until
45  * NINDY indicates that the program has stopped.
46  *
47  *
48  * PASSTHROUGH MODE
49  * ----------- ----
50  *
51  * GDB writes all input received from the keyboard directly to NINDY, and writes
52  * all characters received from NINDY directly to the monitor.
53  *
54  * Keyboard input is neither buffered nor echoed to the monitor.
55  *
56  * GDB remains in passthrough mode until NINDY sends a single ^P character,
57  * to indicate that the user process has stopped.
58  *
59  * Note:
60  *      GDB assumes NINDY performs a 'flushreg' when the user program stops.
61  *
62  *
63  * COMMAND MODE
64  * ------- ----
65  *
66  * All info (except for message ack and nak) is transferred between gdb
67  * and the remote processor in messages of the following format:
68  *
69  *              <info>#<checksum>
70  *
71  * where 
72  *      #       is a literal character
73  *
74  *      <info>  ASCII information;  all numeric information is in the
75  *              form of hex digits ('0'-'9' and lowercase 'a'-'f').
76  *
77  *      <checksum>
78  *              is a pair of ASCII hex digits representing an 8-bit
79  *              checksum formed by adding together each of the
80  *              characters in <info>.
81  *
82  * The receiver of a message always sends a single character to the sender
83  * to indicate that the checksum was good ('+') or bad ('-');  the sender
84  * re-transmits the entire message over until a '+' is received.
85  *
86  * In response to a command NINDY always sends back either data or
87  * a result code of the form "Xnn", where "nn" are hex digits and "X00"
88  * means no errors.  (Exceptions: the "s" and "c" commands don't respond.)
89  *
90  * SEE THE HEADER OF THE FILE "gdb.c" IN THE NINDY MONITOR SOURCE CODE FOR A
91  * FULL DESCRIPTION OF LEGAL COMMANDS.
92  *
93  * SEE THE FILE "stop.h" IN THE NINDY MONITOR SOURCE CODE FOR A LIST
94  * OF STOP CODES.
95  *
96  ***************************************************************************/
97
98 #include "defs.h"
99 #include <signal.h>
100 #include <sys/types.h>
101 #include <setjmp.h>
102
103 #include "frame.h"
104 #include "inferior.h"
105 #include "bfd.h"
106 #include "symfile.h"
107 #include "target.h"
108 #include "gdbcore.h"
109 #include "command.h"
110 #include "ieee-float.h"
111
112 #include "wait.h"
113 #include <sys/file.h>
114 #include <ctype.h>
115 #include "serial.h"
116 #include "nindy-share/env.h"
117 #include "nindy-share/stop.h"
118
119 #include "dcache.h"
120
121 static DCACHE *nindy_dcache;
122
123 extern int unlink();
124 extern char *getenv();
125 extern char *mktemp();
126
127 extern void generic_mourn_inferior ();
128
129 extern struct target_ops nindy_ops;
130 extern FILE *instream;
131 extern struct ext_format ext_format_i960;       /* i960-tdep.c */
132
133 extern char ninStopWhy ();
134
135 int nindy_initial_brk;  /* nonzero if want to send an initial BREAK to nindy */
136 int nindy_old_protocol; /* nonzero if want to use old protocol */
137 char *nindy_ttyname;    /* name of tty to talk to nindy on, or null */
138
139 #define DLE     '\020'  /* Character NINDY sends to indicate user program has
140                          * halted.  */
141 #define TRUE    1
142 #define FALSE   0
143
144 /* From nindy-share/nindy.c.  */
145 extern serial_t nindy_serial;
146
147 static int have_regs = 0;       /* 1 iff regs read since i960 last halted */
148 static int regs_changed = 0;    /* 1 iff regs were modified since last read */
149
150 extern char *exists();
151
152 static void
153 nindy_fetch_registers PARAMS ((int));
154
155 static void
156 nindy_store_registers PARAMS ((int));
157 \f
158 static char *savename;
159
160 static void
161 nindy_close (quitting)
162      int quitting;
163 {
164   if (nindy_serial != NULL)
165     SERIAL_CLOSE (nindy_serial);
166   nindy_serial = NULL;
167
168   if (savename)
169     free (savename);
170   savename = 0;
171 }
172
173 /* Open a connection to a remote debugger.   
174    FIXME, there should be a way to specify the various options that are
175    now specified with gdb command-line options.  (baud_rate, old_protocol,
176    and initial_brk)  */
177 void
178 nindy_open (name, from_tty)
179     char *name;         /* "/dev/ttyXX", "ttyXX", or "XX": tty to be opened */
180     int from_tty;
181 {
182
183   if (!name)
184     error_no_arg ("serial port device name");
185
186   target_preopen (from_tty);
187   
188   nindy_close (0);
189
190   have_regs = regs_changed = 0;
191   nindy_dcache = dcache_init(ninMemGet, ninMemPut);
192
193   /* Allow user to interrupt the following -- we could hang if there's
194      no NINDY at the other end of the remote tty.  */
195   immediate_quit++;
196   ninConnect(name, baud_rate ? baud_rate : "9600",
197              nindy_initial_brk, !from_tty, nindy_old_protocol);
198   immediate_quit--;
199
200   if (nindy_serial == NULL)
201     {
202       perror_with_name (name);
203     }
204
205   savename = savestring (name, strlen (name));
206   push_target (&nindy_ops);
207   target_fetch_registers(-1);
208 }
209
210 /* User-initiated quit of nindy operations.  */
211
212 static void
213 nindy_detach (name, from_tty)
214      char *name;
215      int from_tty;
216 {
217   if (name)
218     error ("Too many arguments");
219   pop_target ();
220 }
221
222 static void
223 nindy_files_info ()
224 {
225   printf("\tAttached to %s at %s bps%s%s.\n", savename,
226          baud_rate? baud_rate: "9600",
227          nindy_old_protocol? " in old protocol": "",
228          nindy_initial_brk? " with initial break": "");
229 }
230 \f
231 /* Return the number of characters in the buffer before
232    the first DLE character.  */
233
234 static
235 int
236 non_dle( buf, n )
237     char *buf;          /* Character buffer; NOT '\0'-terminated */
238     int n;              /* Number of characters in buffer */
239 {
240         int i;
241
242         for ( i = 0; i < n; i++ ){
243                 if ( buf[i] == DLE ){
244                         break;
245                 }
246         }
247         return i;
248 }
249 \f
250 /* Tell the remote machine to resume.  */
251
252 void
253 nindy_resume (pid, step, siggnal)
254      int pid, step, siggnal;
255 {
256         if (siggnal != 0 && siggnal != stop_signal)
257           error ("Can't send signals to remote NINDY targets.");
258
259         dcache_flush(nindy_dcache);
260         if ( regs_changed ){
261                 nindy_store_registers (-1);
262                 regs_changed = 0;
263         }
264         have_regs = 0;
265         ninGo( step );
266 }
267 \f
268 /* FIXME, we can probably use the normal terminal_inferior stuff here.
269    We have to do terminal_inferior and then set up the passthrough
270    settings initially.  Thereafter, terminal_ours and terminal_inferior
271    will automatically swap the settings around for us.  */
272
273 struct clean_up_tty_args {
274   serial_ttystate state;
275   serial_t serial;
276 };
277
278 static void
279 clean_up_tty (ptrarg)
280      PTR ptrarg;
281 {
282   struct clean_up_tty_args *args = (struct clean_up_tty_args *) ptrarg;
283   SERIAL_SET_TTY_STATE (args->serial, args->state);
284   free (args->state);
285   warning ("\n\n\
286 You may need to reset the 80960 and/or reload your program.\n");
287 }
288
289 /* Wait until the remote machine stops. While waiting, operate in passthrough
290  * mode; i.e., pass everything NINDY sends to stdout, and everything from
291  * stdin to NINDY.
292  *
293  * Return to caller, storing status in 'status' just as `wait' would.
294  */
295
296 static int
297 nindy_wait( status )
298     WAITTYPE *status;
299 {
300   fd_set fds;
301   char buf[500];        /* FIXME, what is "500" here? */
302   int i, n;
303   unsigned char stop_exit;
304   unsigned char stop_code;
305   struct clean_up_tty_args tty_args;
306   struct cleanup *old_cleanups;
307   long ip_value, fp_value, sp_value;    /* Reg values from stop */
308
309   WSETEXIT( (*status), 0 );
310
311   /* OPERATE IN PASSTHROUGH MODE UNTIL NINDY SENDS A DLE CHARACTER */
312
313   /* Save current tty attributes, and restore them when done.  */
314   tty_args.serial = SERIAL_FDOPEN (0);
315   tty_args.state = SERIAL_GET_TTY_STATE (tty_args.serial);
316   old_cleanups = make_cleanup (clean_up_tty, &tty_args);
317
318   /* Pass input from keyboard to NINDY as it arrives.  NINDY will interpret
319      <CR> and perform echo.  */
320   /* This used to set CBREAK and clear ECHO and CRMOD.  I hope this is close
321      enough.  */
322   SERIAL_RAW (tty_args.serial);
323
324   while (1)
325     {
326       /* Wait for input on either the remote port or stdin.  */
327       FD_ZERO (&fds);
328       FD_SET (0, &fds);
329       FD_SET (nindy_serial->fd, &fds);
330       if (select (nindy_serial->fd + 1, &fds, 0, 0, 0) <= 0)
331         continue;
332
333       /* Pass input through to correct place */
334       if (FD_ISSET (0, &fds))
335         {
336           /* Input on stdin */
337           n = read (0, buf, sizeof (buf));
338           if (n)
339             {
340               SERIAL_WRITE (nindy_serial, buf, n );
341             }
342         }
343
344       if (FD_ISSET (nindy_serial->fd, &fds))
345         {
346           /* Input on remote */
347           n = read (nindy_serial->fd, buf, sizeof (buf));
348           if (n)
349             {
350               /* Write out any characters in buffer preceding DLE */
351               i = non_dle( buf, n );
352               if ( i > 0 )
353                 {
354                   write (1, buf, i);
355                 }
356
357               if (i != n)
358                 {
359                   /* There *was* a DLE in the buffer */
360                   stop_exit = ninStopWhy(&stop_code,
361                                          &ip_value, &fp_value, &sp_value);
362                   if (!stop_exit && (stop_code == STOP_SRQ))
363                     {
364                       immediate_quit++;
365                       ninSrq();
366                       immediate_quit--;
367                     }
368                   else
369                     {
370                       /* Get out of loop */
371                       supply_register (IP_REGNUM, 
372                                        (char *)&ip_value);
373                       supply_register (FP_REGNUM, 
374                                        (char *)&fp_value);
375                       supply_register (SP_REGNUM, 
376                                        (char *)&sp_value);
377                       break;
378                     }
379                 }
380             }
381         }
382     }
383
384   do_cleanups (old_cleanups);
385
386   if (stop_exit)
387     {
388       /* User program exited */
389       WSETEXIT ((*status), stop_code);
390     }
391   else
392     {
393       /* Fault or trace */
394       switch (stop_code)
395         {
396         case STOP_GDB_BPT:
397         case TRACE_STEP:
398           /* Breakpoint or single stepping.  */
399           stop_code = SIGTRAP;
400           break;
401         default:
402           /* The target is not running Unix, and its faults/traces do
403              not map nicely into Unix signals.  Make sure they do not
404              get confused with Unix signals by numbering them with
405              values higher than the highest legal Unix signal.  code
406              in i960_print_fault(), called via PRINT_RANDOM_SIGNAL,
407              will interpret the value.  */
408           stop_code += NSIG;
409           break;
410         }
411       WSETSTOP ((*status), stop_code);
412     }
413   return inferior_pid;
414 }
415
416 /* Read the remote registers into the block REGS.  */
417
418 /* This is the block that ninRegsGet and ninRegsPut handles.  */
419 struct nindy_regs {
420   char  local_regs[16 * 4];
421   char  global_regs[16 * 4];
422   char  pcw_acw[2 * 4];
423   char  ip[4];
424   char  tcw[4];
425   char  fp_as_double[4 * 8];
426 };
427
428 static void
429 nindy_fetch_registers(regno)
430      int regno;
431 {
432   struct nindy_regs nindy_regs;
433   int regnum, inv;
434   double dub;
435
436   immediate_quit++;
437   ninRegsGet( (char *) &nindy_regs );
438   immediate_quit--;
439
440   memcpy (&registers[REGISTER_BYTE (R0_REGNUM)], nindy_regs.local_regs, 16*4);
441   memcpy (&registers[REGISTER_BYTE (G0_REGNUM)], nindy_regs.global_regs, 16*4);
442   memcpy (&registers[REGISTER_BYTE (PCW_REGNUM)], nindy_regs.pcw_acw, 2*4);
443   memcpy (&registers[REGISTER_BYTE (IP_REGNUM)], nindy_regs.ip, 1*4);
444   memcpy (&registers[REGISTER_BYTE (TCW_REGNUM)], nindy_regs.tcw, 1*4);
445   for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++) {
446     dub = unpack_double (builtin_type_double,
447                          &nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)],
448                          &inv);
449     /* dub now in host byte order */
450     double_to_ieee_extended (&ext_format_i960, &dub,
451                              &registers[REGISTER_BYTE (regnum)]);
452   }
453
454   registers_fetched ();
455 }
456
457 static void
458 nindy_prepare_to_store()
459 {
460   /* Fetch all regs if they aren't already here.  */
461   read_register_bytes (0, NULL, REGISTER_BYTES);
462 }
463
464 static void
465 nindy_store_registers(regno)
466      int regno;
467 {
468   struct nindy_regs nindy_regs;
469   int regnum, inv;
470   double dub;
471
472   memcpy (nindy_regs.local_regs, &registers[REGISTER_BYTE (R0_REGNUM)], 16*4);
473   memcpy (nindy_regs.global_regs, &registers[REGISTER_BYTE (G0_REGNUM)], 16*4);
474   memcpy (nindy_regs.pcw_acw, &registers[REGISTER_BYTE (PCW_REGNUM)], 2*4);
475   memcpy (nindy_regs.ip, &registers[REGISTER_BYTE (IP_REGNUM)], 1*4);
476   memcpy (nindy_regs.tcw, &registers[REGISTER_BYTE (TCW_REGNUM)], 1*4);
477   /* Float regs.  Only works on IEEE_FLOAT hosts.  FIXME!  */
478   for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++) {
479     ieee_extended_to_double (&ext_format_i960,
480                              &registers[REGISTER_BYTE (regnum)], &dub);
481     /* dub now in host byte order */
482     /* FIXME-someday, the arguments to unpack_double are backward.
483        It expects a target double and returns a host; we pass the opposite.
484        This mostly works but not quite.  */
485     dub = unpack_double (builtin_type_double, (char *)&dub, &inv);
486     /* dub now in target byte order */
487     memcpy (&nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)], &dub, 8);
488   }
489
490   immediate_quit++;
491   ninRegsPut( (char *) &nindy_regs );
492   immediate_quit--;
493 }
494
495 /* Read a word from remote address ADDR and return it.
496  * This goes through the data cache.
497  */
498 int
499 nindy_fetch_word (addr)
500      CORE_ADDR addr;
501 {
502         return dcache_fetch (nindy_dcache, addr);
503 }
504
505 /* Write a word WORD into remote address ADDR.
506    This goes through the data cache.  */
507
508 void
509 nindy_store_word (addr, word)
510      CORE_ADDR addr;
511      int word;
512 {
513         dcache_poke (nindy_dcache, addr, word);
514 }
515
516 /* Copy LEN bytes to or from inferior's memory starting at MEMADDR
517    to debugger memory starting at MYADDR.   Copy to inferior if
518    WRITE is nonzero.  Returns the length copied.
519
520    This is stolen almost directly from infptrace.c's child_xfer_memory,
521    which also deals with a word-oriented memory interface.  Sometime,
522    FIXME, rewrite this to not use the word-oriented routines.  */
523
524 int
525 nindy_xfer_inferior_memory(memaddr, myaddr, len, write, target)
526      CORE_ADDR memaddr;
527      char *myaddr;
528      int len;
529      int write;
530      struct target_ops *target;                 /* ignored */
531 {
532   register int i;
533   /* Round starting address down to longword boundary.  */
534   register CORE_ADDR addr = memaddr & - sizeof (int);
535   /* Round ending address up; get number of longwords that makes.  */
536   register int count
537     = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
538   /* Allocate buffer of that many longwords.  */
539   register int *buffer = (int *) alloca (count * sizeof (int));
540
541   if (write)
542     {
543       /* Fill start and end extra bytes of buffer with existing memory data.  */
544
545       if (addr != memaddr || len < (int)sizeof (int)) {
546         /* Need part of initial word -- fetch it.  */
547         buffer[0] = nindy_fetch_word (addr);
548       }
549
550       if (count > 1)            /* FIXME, avoid if even boundary */
551         {
552           buffer[count - 1]
553             = nindy_fetch_word (addr + (count - 1) * sizeof (int));
554         }
555
556       /* Copy data to be written over corresponding part of buffer */
557
558       memcpy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
559
560       /* Write the entire buffer.  */
561
562       for (i = 0; i < count; i++, addr += sizeof (int))
563         {
564           errno = 0;
565           nindy_store_word (addr, buffer[i]);
566           if (errno)
567             return 0;
568         }
569     }
570   else
571     {
572       /* Read all the longwords */
573       for (i = 0; i < count; i++, addr += sizeof (int))
574         {
575           errno = 0;
576           buffer[i] = nindy_fetch_word (addr);
577           if (errno)
578             return 0;
579           QUIT;
580         }
581
582       /* Copy appropriate bytes out of the buffer.  */
583       memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
584     }
585   return len;
586 }
587 \f
588 static void
589 nindy_create_inferior (execfile, args, env)
590      char *execfile;
591      char *args;
592      char **env;
593 {
594   int entry_pt;
595   int pid;
596
597   if (args && *args)
598     error ("Can't pass arguments to remote NINDY process");
599
600   if (execfile == 0 || exec_bfd == 0)
601     error ("No exec file specified");
602
603   entry_pt = (int) bfd_get_start_address (exec_bfd);
604
605   pid = 42;
606
607 #ifdef CREATE_INFERIOR_HOOK
608   CREATE_INFERIOR_HOOK (pid);
609 #endif  
610
611 /* The "process" (board) is already stopped awaiting our commands, and
612    the program is already downloaded.  We just set its PC and go.  */
613
614   inferior_pid = pid;           /* Needed for wait_for_inferior below */
615
616   clear_proceed_status ();
617
618   /* Tell wait_for_inferior that we've started a new process.  */
619   init_wait_for_inferior ();
620
621   /* Set up the "saved terminal modes" of the inferior
622      based on what modes we are starting it with.  */
623   target_terminal_init ();
624
625   /* Install inferior's terminal modes.  */
626   target_terminal_inferior ();
627
628   /* insert_step_breakpoint ();  FIXME, do we need this?  */
629   proceed ((CORE_ADDR)entry_pt, -1, 0);         /* Let 'er rip... */
630 }
631
632 static void
633 reset_command(args, from_tty)
634      char *args;
635      int from_tty;
636 {
637   if (nindy_serial == NULL)
638     {
639       error( "No target system to reset -- use 'target nindy' command.");
640     }
641   if ( query("Really reset the target system?",0,0) )
642     {
643       SERIAL_SEND_BREAK (nindy_serial);
644       tty_flush (nindy_serial);
645     }
646 }
647
648 void
649 nindy_kill (args, from_tty)
650      char *args;
651      int from_tty;
652 {
653   return;               /* Ignore attempts to kill target system */
654 }
655
656 /* Clean up when a program exits.
657
658    The program actually lives on in the remote processor's RAM, and may be
659    run again without a download.  Don't leave it full of breakpoint
660    instructions.  */
661
662 void
663 nindy_mourn_inferior ()
664 {
665   remove_breakpoints ();
666   unpush_target (&nindy_ops);
667   generic_mourn_inferior ();    /* Do all the proper things now */
668 }
669 \f
670 /* Pass the args the way catch_errors wants them.  */
671 static int
672 nindy_open_stub (arg)
673      char *arg;
674 {
675   nindy_open (arg, 1);
676   return 1;
677 }
678
679 static int
680 load_stub (arg)
681      char *arg;
682 {
683   target_load (arg, 1);
684   return 1;
685 }
686
687 /* This routine is run as a hook, just before the main command loop is
688    entered.  If gdb is configured for the i960, but has not had its
689    nindy target specified yet, this will loop prompting the user to do so.
690
691    Unlike the loop provided by Intel, we actually let the user get out
692    of this with a RETURN.  This is useful when e.g. simply examining
693    an i960 object file on the host system.  */
694
695 void
696 nindy_before_main_loop ()
697 {
698   char ttyname[100];
699   char *p, *p2;
700
701   while (current_target != &nindy_ops) { /* remote tty not specified yet */
702         if ( instream == stdin ){
703                 printf("\nAttach /dev/ttyNN -- specify NN, or \"quit\" to quit:  ");
704                 fflush( stdout );
705         }
706         fgets( ttyname, sizeof(ttyname)-1, stdin );
707
708         /* Strip leading and trailing whitespace */
709         for ( p = ttyname; isspace(*p); p++ ){
710                 ;
711         }
712         if ( *p == '\0' ){
713                 return;         /* User just hit spaces or return, wants out */
714         }
715         for ( p2= p; !isspace(*p2) && (*p2 != '\0'); p2++ ){
716                 ;
717         }
718         *p2= '\0';
719         if ( STREQ("quit",p) ){
720                 exit(1);
721         }
722
723         if (catch_errors (nindy_open_stub, p, "", RETURN_MASK_ALL))
724           {
725             /* Now that we have a tty open for talking to the remote machine,
726                download the executable file if one was specified.  */
727             if (exec_bfd)
728               {
729                 catch_errors (load_stub, bfd_get_filename (exec_bfd), "",
730                               RETURN_MASK_ALL);
731               }
732           }
733   }
734 }
735 \f
736 /* Define the target subroutine names */
737
738 struct target_ops nindy_ops = {
739         "nindy", "Remote serial target in i960 NINDY-specific protocol",
740         "Use a remote i960 system running NINDY connected by a serial line.\n\
741 Specify the name of the device the serial line is connected to.\n\
742 The speed (baud rate), whether to use the old NINDY protocol,\n\
743 and whether to send a break on startup, are controlled by options\n\
744 specified when you started GDB.",
745         nindy_open, nindy_close,
746         0,
747         nindy_detach,
748         nindy_resume,
749         nindy_wait,
750         nindy_fetch_registers, nindy_store_registers,
751         nindy_prepare_to_store,
752         nindy_xfer_inferior_memory, nindy_files_info,
753         0, 0, /* insert_breakpoint, remove_breakpoint, */
754         0, 0, 0, 0, 0,  /* Terminal crud */
755         nindy_kill,
756         generic_load,
757         0, /* lookup_symbol */
758         nindy_create_inferior,
759         nindy_mourn_inferior,
760         0,              /* can_run */
761         0, /* notice_signals */
762         process_stratum, 0, /* next */
763         1, 1, 1, 1, 1,  /* all mem, mem, stack, regs, exec */
764         0, 0,                   /* Section pointers */
765         OPS_MAGIC,              /* Always the last thing */
766 };
767
768 void
769 _initialize_nindy ()
770 {
771   add_target (&nindy_ops);
772   add_com ("reset", class_obscure, reset_command,
773            "Send a 'break' to the remote target system.\n\
774 Only useful if the target has been equipped with a circuit\n\
775 to perform a hard reset when a break is detected.");
776 }