* Remote targets (mourn): Call unpush_target.
[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 "target.h"
106 #include "gdbcore.h"
107 #include "command.h"
108 #include "bfd.h"
109 #include "ieee-float.h"
110
111 #include "wait.h"
112 #include <sys/ioctl.h>
113 #include <sys/file.h>
114 #include <ctype.h>
115 #include "nindy-share/ttycntl.h"
116 #include "nindy-share/demux.h"
117 #include "nindy-share/env.h"
118 #include "nindy-share/stop.h"
119
120 extern int unlink();
121 extern char *getenv();
122 extern char *mktemp();
123
124 extern char *coffstrip();
125 extern void generic_mourn_inferior ();
126
127 extern struct target_ops nindy_ops;
128 extern jmp_buf to_top_level;
129 extern FILE *instream;
130 extern struct ext_format ext_format_i960;       /* i960-tdep.c */
131
132 extern char ninStopWhy ();
133
134 int nindy_initial_brk;  /* nonzero if want to send an initial BREAK to nindy */
135 int nindy_old_protocol; /* nonzero if want to use old protocol */
136 char *nindy_ttyname;    /* name of tty to talk to nindy on, or null */
137
138 #define DLE     '\020'  /* Character NINDY sends to indicate user program has
139                          * halted.  */
140 #define TRUE    1
141 #define FALSE   0
142
143 int nindy_fd = 0;       /* Descriptor for I/O to NINDY  */
144 static int have_regs = 0;       /* 1 iff regs read since i960 last halted */
145 static int regs_changed = 0;    /* 1 iff regs were modified since last read */
146
147 extern char *exists();
148
149 static void
150 dcache_flush (), dcache_poke (), dcache_init();
151
152 static int
153 dcache_fetch ();
154
155 static void
156 nindy_fetch_registers PARAMS ((int));
157
158 static void
159 nindy_store_registers PARAMS ((int));
160 \f
161 /* FIXME, we can probably use the normal terminal_inferior stuff here.
162    We have to do terminal_inferior and then set up the passthrough
163    settings initially.  Thereafter, terminal_ours and terminal_inferior
164    will automatically swap the settings around for us.  */
165
166 /* Restore TTY to normal operation */
167
168 static TTY_STRUCT orig_tty;     /* TTY attributes before entering passthrough */
169
170 static void
171 restore_tty()
172 {
173         ioctl( 0, TIOCSETN, &orig_tty );
174 }
175
176
177 /* Recover from ^Z or ^C while remote process is running */
178
179 static void (*old_ctrlc)();    /* Signal handlers before entering passthrough */
180
181 #ifdef SIGTSTP
182 static void (*old_ctrlz)();
183 #endif
184
185 static
186 #ifdef USG
187 void
188 #endif
189 cleanup()
190 {
191         restore_tty();
192         signal(SIGINT, old_ctrlc);
193 #ifdef SIGTSTP
194         signal(SIGTSTP, old_ctrlz);
195 #endif
196         error("\n\nYou may need to reset the 80960 and/or reload your program.\n");
197 }
198 \f
199 /* Clean up anything that needs cleaning when losing control.  */
200
201 static char *savename;
202
203 static void
204 nindy_close (quitting)
205      int quitting;
206 {
207   if (nindy_fd)
208     close (nindy_fd);
209   nindy_fd = 0;
210
211   if (savename)
212     free (savename);
213   savename = 0;
214 }
215
216 /* Open a connection to a remote debugger.   
217    FIXME, there should be a way to specify the various options that are
218    now specified with gdb command-line options.  (baud_rate, old_protocol,
219    and initial_brk)  */
220 void
221 nindy_open (name, from_tty)
222     char *name;         /* "/dev/ttyXX", "ttyXX", or "XX": tty to be opened */
223     int from_tty;
224 {
225
226   if (!name)
227     error_no_arg ("serial port device name");
228
229   target_preopen (from_tty);
230   
231   nindy_close (0);
232
233         have_regs = regs_changed = 0;
234         dcache_init();
235
236         /* Allow user to interrupt the following -- we could hang if
237          * there's no NINDY at the other end of the remote tty.
238          */
239         immediate_quit++;
240         nindy_fd = ninConnect( name, baud_rate? baud_rate: "9600",
241                         nindy_initial_brk, !from_tty, nindy_old_protocol );
242         immediate_quit--;
243
244         if ( nindy_fd < 0 ){
245                 nindy_fd = 0;
246                 error( "Can't open tty '%s'", name );
247         }
248
249         savename = savestring (name, strlen (name));
250         push_target (&nindy_ops);
251         target_fetch_registers(-1);
252 }
253
254 /* User-initiated quit of nindy operations.  */
255
256 static void
257 nindy_detach (name, from_tty)
258      char *name;
259      int from_tty;
260 {
261   if (name)
262     error ("Too many arguments");
263   pop_target ();
264 }
265
266 static void
267 nindy_files_info ()
268 {
269   printf("\tAttached to %s at %s bps%s%s.\n", savename,
270          baud_rate? baud_rate: "9600",
271          nindy_old_protocol? " in old protocol": "",
272          nindy_initial_brk? " with initial break": "");
273 }
274 \f
275 /******************************************************************************
276  * remote_load:
277  *      Download an object file to the remote system by invoking the "comm960"
278  *      utility.  We look for "comm960" in $G960BIN, $G960BASE/bin, and
279  *      DEFAULT_BASE/bin/HOST/bin where
280  *              DEFAULT_BASE is defined in env.h, and
281  *              HOST must be defined on the compiler invocation line.
282  ******************************************************************************/
283
284 static void
285 nindy_load( filename, from_tty )
286     char *filename;
287     int from_tty;
288 {
289   asection *s;
290   /* Can't do unix style forking on a VMS system, so we'll use bfd to do
291      all the work for us 
292      */
293
294   bfd *file = bfd_openr(filename,0);
295   if (!file) 
296   {
297     perror_with_name(filename);
298     return;
299   }
300   
301   if (!bfd_check_format(file, bfd_object)) 
302   {
303     error("can't prove it's an object file\n");
304     return;
305   }
306   
307   for ( s = file->sections; s; s=s->next) 
308   {
309     if (s->flags & SEC_LOAD) 
310     {
311       char *buffer = xmalloc(s->_raw_size);
312       bfd_get_section_contents(file, s, buffer, 0, s->_raw_size);
313       printf("Loading section %s, size %x vma %x\n",
314              s->name, 
315              s->_raw_size,
316              s->vma);
317       ninMemPut(s->vma, buffer, s->_raw_size);
318       free(buffer);
319     }
320   }
321   bfd_close(file);
322 }
323
324 /* Return the number of characters in the buffer before the first DLE character.
325  */
326
327 static
328 int
329 non_dle( buf, n )
330     char *buf;          /* Character buffer; NOT '\0'-terminated */
331     int n;              /* Number of characters in buffer */
332 {
333         int i;
334
335         for ( i = 0; i < n; i++ ){
336                 if ( buf[i] == DLE ){
337                         break;
338                 }
339         }
340         return i;
341 }
342 \f
343 /* Tell the remote machine to resume.  */
344
345 void
346 nindy_resume (step, siggnal)
347      int step, siggnal;
348 {
349         if (siggnal != 0 && siggnal != stop_signal)
350           error ("Can't send signals to remote NINDY targets.");
351
352         dcache_flush();
353         if ( regs_changed ){
354                 nindy_store_registers (-1);
355                 regs_changed = 0;
356         }
357         have_regs = 0;
358         ninGo( step );
359 }
360
361 /* Wait until the remote machine stops. While waiting, operate in passthrough
362  * mode; i.e., pass everything NINDY sends to stdout, and everything from
363  * stdin to NINDY.
364  *
365  * Return to caller, storing status in 'status' just as `wait' would.
366  */
367
368 static int
369 nindy_wait( status )
370     WAITTYPE *status;
371 {
372         DEMUX_DECL;     /* OS-dependent data needed by DEMUX... macros */
373         char buf[500];  /* FIXME, what is "500" here? */
374         int i, n;
375         unsigned char stop_exit;
376         unsigned char stop_code;
377         TTY_STRUCT tty;
378         long ip_value, fp_value, sp_value;      /* Reg values from stop */
379
380
381         WSETEXIT( (*status), 0 );
382
383         /* OPERATE IN PASSTHROUGH MODE UNTIL NINDY SENDS A DLE CHARACTER */
384
385         /* Save current tty attributes, set up signals to restore them.
386          */
387         ioctl( 0, TIOCGETP, &orig_tty );
388         old_ctrlc = signal( SIGINT, cleanup );
389 #ifdef SIGTSTP
390         old_ctrlz = signal( SIGTSTP, cleanup );
391 #endif
392
393         /* Pass input from keyboard to NINDY as it arrives.
394          * NINDY will interpret <CR> and perform echo.
395          */
396         tty = orig_tty;
397         TTY_NINDYTERM( tty );
398         ioctl( 0, TIOCSETN, &tty );
399
400         while ( 1 ){
401                 /* Go to sleep until there's something for us on either
402                  * the remote port or stdin.
403                  */
404
405                 DEMUX_WAIT( nindy_fd );
406
407                 /* Pass input through to correct place */
408
409                 n = DEMUX_READ( 0, buf, sizeof(buf) );
410                 if ( n ){                               /* Input on stdin */
411                         write( nindy_fd, buf, n );
412                 }
413
414                 n = DEMUX_READ( nindy_fd, buf, sizeof(buf) );
415                 if ( n ){                               /* Input on remote */
416                         /* Write out any characters in buffer preceding DLE */
417                         i = non_dle( buf, n );
418                         if ( i > 0 ){
419                                 write( 1, buf, i );
420                         }
421
422                         if ( i != n ){
423                                 /* There *was* a DLE in the buffer */
424                                 stop_exit = ninStopWhy( &stop_code,
425                                         &ip_value, &fp_value, &sp_value);
426                                 if ( !stop_exit && (stop_code==STOP_SRQ) ){
427                                         immediate_quit++;
428                                         ninSrq();
429                                         immediate_quit--;
430                                 } else {
431                                         /* Get out of loop */
432                                         supply_register (IP_REGNUM, 
433                                                          (char *)&ip_value);
434                                         supply_register (FP_REGNUM, 
435                                                          (char *)&fp_value);
436                                         supply_register (SP_REGNUM, 
437                                                          (char *)&sp_value);
438                                         break;
439                                 }
440                         }
441                 }
442         }
443
444         signal( SIGINT, old_ctrlc );
445 #ifdef SIGTSTP
446         signal( SIGTSTP, old_ctrlz );
447 #endif
448         restore_tty();
449
450         if ( stop_exit ){                       /* User program exited */
451                 WSETEXIT( (*status), stop_code );
452         } else {                                /* Fault or trace */
453                 switch (stop_code){
454                 case STOP_GDB_BPT:
455                 case TRACE_STEP:
456                         /* Make it look like a VAX trace trap */
457                         stop_code = SIGTRAP;
458                         break;
459                 default:
460                         /* The target is not running Unix, and its
461                            faults/traces do not map nicely into Unix signals.
462                            Make sure they do not get confused with Unix signals
463                            by numbering them with values higher than the highest
464                            legal Unix signal.  code in i960_print_fault(),
465                            called via PRINT_RANDOM_SIGNAL, will interpret the
466                            value.  */
467                         stop_code += NSIG;
468                         break;
469                 }
470                 WSETSTOP( (*status), stop_code );
471         }
472         return inferior_pid;
473 }
474
475 /* Read the remote registers into the block REGS.  */
476
477 /* This is the block that ninRegsGet and ninRegsPut handles.  */
478 struct nindy_regs {
479   char  local_regs[16 * 4];
480   char  global_regs[16 * 4];
481   char  pcw_acw[2 * 4];
482   char  ip[4];
483   char  tcw[4];
484   char  fp_as_double[4 * 8];
485 };
486
487 static void
488 nindy_fetch_registers(regno)
489      int regno;
490 {
491   struct nindy_regs nindy_regs;
492   int regnum, inv;
493   double dub;
494
495   immediate_quit++;
496   ninRegsGet( (char *) &nindy_regs );
497   immediate_quit--;
498
499   bcopy (nindy_regs.local_regs, &registers[REGISTER_BYTE (R0_REGNUM)], 16*4);
500   bcopy (nindy_regs.global_regs, &registers[REGISTER_BYTE (G0_REGNUM)], 16*4);
501   bcopy (nindy_regs.pcw_acw, &registers[REGISTER_BYTE (PCW_REGNUM)], 2*4);
502   bcopy (nindy_regs.ip, &registers[REGISTER_BYTE (IP_REGNUM)], 1*4);
503   bcopy (nindy_regs.tcw, &registers[REGISTER_BYTE (TCW_REGNUM)], 1*4);
504   for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++) {
505     dub = unpack_double (builtin_type_double,
506                          &nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)],
507                          &inv);
508     /* dub now in host byte order */
509     double_to_ieee_extended (&ext_format_i960, &dub,
510                              &registers[REGISTER_BYTE (regnum)]);
511   }
512
513   registers_fetched ();
514 }
515
516 static void
517 nindy_prepare_to_store()
518 {
519   /* Fetch all regs if they aren't already here.  */
520   read_register_bytes (0, NULL, REGISTER_BYTES);
521 }
522
523 static void
524 nindy_store_registers(regno)
525      int regno;
526 {
527   struct nindy_regs nindy_regs;
528   int regnum, inv;
529   double dub;
530
531   bcopy (&registers[REGISTER_BYTE (R0_REGNUM)], nindy_regs.local_regs,  16*4);
532   bcopy (&registers[REGISTER_BYTE (G0_REGNUM)], nindy_regs.global_regs, 16*4);
533   bcopy (&registers[REGISTER_BYTE (PCW_REGNUM)], nindy_regs.pcw_acw,     2*4);
534   bcopy (&registers[REGISTER_BYTE (IP_REGNUM)], nindy_regs.ip,           1*4);
535   bcopy (&registers[REGISTER_BYTE (TCW_REGNUM)], nindy_regs.tcw,         1*4);
536   /* Float regs.  Only works on IEEE_FLOAT hosts.  FIXME!  */
537   for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++) {
538     ieee_extended_to_double (&ext_format_i960,
539                              &registers[REGISTER_BYTE (regnum)], &dub);
540     /* dub now in host byte order */
541     /* FIXME-someday, the arguments to unpack_double are backward.
542        It expects a target double and returns a host; we pass the opposite.
543        This mostly works but not quite.  */
544     dub = unpack_double (builtin_type_double, (char *)&dub, &inv);
545     /* dub now in target byte order */
546     bcopy ((char *)&dub, &nindy_regs.fp_as_double[8 * (regnum - FP0_REGNUM)],
547         8);
548   }
549
550   immediate_quit++;
551   ninRegsPut( (char *) &nindy_regs );
552   immediate_quit--;
553 }
554
555 /* Read a word from remote address ADDR and return it.
556  * This goes through the data cache.
557  */
558 int
559 nindy_fetch_word (addr)
560      CORE_ADDR addr;
561 {
562         return dcache_fetch (addr);
563 }
564
565 /* Write a word WORD into remote address ADDR.
566    This goes through the data cache.  */
567
568 void
569 nindy_store_word (addr, word)
570      CORE_ADDR addr;
571      int word;
572 {
573         dcache_poke (addr, word);
574 }
575
576 /* Copy LEN bytes to or from inferior's memory starting at MEMADDR
577    to debugger memory starting at MYADDR.   Copy to inferior if
578    WRITE is nonzero.  Returns the length copied.
579
580    This is stolen almost directly from infptrace.c's child_xfer_memory,
581    which also deals with a word-oriented memory interface.  Sometime,
582    FIXME, rewrite this to not use the word-oriented routines.  */
583
584 int
585 nindy_xfer_inferior_memory(memaddr, myaddr, len, write, target)
586      CORE_ADDR memaddr;
587      char *myaddr;
588      int len;
589      int write;
590      struct target_ops *target;                 /* ignored */
591 {
592   register int i;
593   /* Round starting address down to longword boundary.  */
594   register CORE_ADDR addr = memaddr & - sizeof (int);
595   /* Round ending address up; get number of longwords that makes.  */
596   register int count
597     = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
598   /* Allocate buffer of that many longwords.  */
599   register int *buffer = (int *) alloca (count * sizeof (int));
600
601   if (write)
602     {
603       /* Fill start and end extra bytes of buffer with existing memory data.  */
604
605       if (addr != memaddr || len < (int)sizeof (int)) {
606         /* Need part of initial word -- fetch it.  */
607         buffer[0] = nindy_fetch_word (addr);
608       }
609
610       if (count > 1)            /* FIXME, avoid if even boundary */
611         {
612           buffer[count - 1]
613             = nindy_fetch_word (addr + (count - 1) * sizeof (int));
614         }
615
616       /* Copy data to be written over corresponding part of buffer */
617
618       bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
619
620       /* Write the entire buffer.  */
621
622       for (i = 0; i < count; i++, addr += sizeof (int))
623         {
624           errno = 0;
625           nindy_store_word (addr, buffer[i]);
626           if (errno)
627             return 0;
628         }
629     }
630   else
631     {
632       /* Read all the longwords */
633       for (i = 0; i < count; i++, addr += sizeof (int))
634         {
635           errno = 0;
636           buffer[i] = nindy_fetch_word (addr);
637           if (errno)
638             return 0;
639           QUIT;
640         }
641
642       /* Copy appropriate bytes out of the buffer.  */
643       bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
644     }
645   return len;
646 }
647 \f
648 /* The data cache records all the data read from the remote machine
649    since the last time it stopped.
650
651    Each cache block holds 16 bytes of data
652    starting at a multiple-of-16 address.  */
653
654 #define DCACHE_SIZE 64          /* Number of cache blocks */
655
656 struct dcache_block {
657         struct dcache_block *next, *last;
658         unsigned int addr;      /* Address for which data is recorded.  */
659         int data[4];
660 };
661
662 struct dcache_block dcache_free, dcache_valid;
663
664 /* Free all the data cache blocks, thus discarding all cached data.  */ 
665 static
666 void
667 dcache_flush ()
668 {
669   register struct dcache_block *db;
670
671   while ((db = dcache_valid.next) != &dcache_valid)
672     {
673       remque (db);
674       insque (db, &dcache_free);
675     }
676 }
677
678 /*
679  * If addr is present in the dcache, return the address of the block
680  * containing it.
681  */
682 static
683 struct dcache_block *
684 dcache_hit (addr)
685      unsigned int addr;
686 {
687   register struct dcache_block *db;
688
689   if (addr & 3)
690     abort ();
691
692   /* Search all cache blocks for one that is at this address.  */
693   db = dcache_valid.next;
694   while (db != &dcache_valid)
695     {
696       if ((addr & 0xfffffff0) == db->addr)
697         return db;
698       db = db->next;
699     }
700   return NULL;
701 }
702
703 /*  Return the int data at address ADDR in dcache block DC.  */
704 static
705 int
706 dcache_value (db, addr)
707      struct dcache_block *db;
708      unsigned int addr;
709 {
710   if (addr & 3)
711     abort ();
712   return (db->data[(addr>>2)&3]);
713 }
714
715 /* Get a free cache block, put or keep it on the valid list,
716    and return its address.  The caller should store into the block
717    the address and data that it describes, then remque it from the
718    free list and insert it into the valid list.  This procedure
719    prevents errors from creeping in if a ninMemGet is interrupted
720    (which used to put garbage blocks in the valid list...).  */
721 static
722 struct dcache_block *
723 dcache_alloc ()
724 {
725   register struct dcache_block *db;
726
727   if ((db = dcache_free.next) == &dcache_free)
728     {
729       /* If we can't get one from the free list, take last valid and put
730          it on the free list.  */
731       db = dcache_valid.last;
732       remque (db);
733       insque (db, &dcache_free);
734     }
735
736   remque (db);
737   insque (db, &dcache_valid);
738   return (db);
739 }
740
741 /* Return the contents of the word at address ADDR in the remote machine,
742    using the data cache.  */
743 static
744 int
745 dcache_fetch (addr)
746      CORE_ADDR addr;
747 {
748   register struct dcache_block *db;
749
750   db = dcache_hit (addr);
751   if (db == 0)
752     {
753       db = dcache_alloc ();
754       immediate_quit++;
755       ninMemGet(addr & ~0xf, (unsigned char *)db->data, 16);
756       immediate_quit--;
757       db->addr = addr & ~0xf;
758       remque (db);                      /* Off the free list */
759       insque (db, &dcache_valid);       /* On the valid list */
760     }
761   return (dcache_value (db, addr));
762 }
763
764 /* Write the word at ADDR both in the data cache and in the remote machine.  */
765 static void
766 dcache_poke (addr, data)
767      CORE_ADDR addr;
768      int data;
769 {
770   register struct dcache_block *db;
771
772   /* First make sure the word is IN the cache.  DB is its cache block.  */
773   db = dcache_hit (addr);
774   if (db == 0)
775     {
776       db = dcache_alloc ();
777       immediate_quit++;
778       ninMemGet(addr & ~0xf, (unsigned char *)db->data, 16);
779       immediate_quit--;
780       db->addr = addr & ~0xf;
781       remque (db);                      /* Off the free list */
782       insque (db, &dcache_valid);       /* On the valid list */
783     }
784
785   /* Modify the word in the cache.  */
786   db->data[(addr>>2)&3] = data;
787
788   /* Send the changed word.  */
789   immediate_quit++;
790   ninMemPut(addr, (unsigned char *)&data, 4);
791   immediate_quit--;
792 }
793
794 /* The cache itself. */
795 struct dcache_block the_cache[DCACHE_SIZE];
796
797 /* Initialize the data cache.  */
798 static void
799 dcache_init ()
800 {
801   register i;
802   register struct dcache_block *db;
803
804   db = the_cache;
805   dcache_free.next = dcache_free.last = &dcache_free;
806   dcache_valid.next = dcache_valid.last = &dcache_valid;
807   for (i=0;i<DCACHE_SIZE;i++,db++)
808     insque (db, &dcache_free);
809 }
810
811
812 static void
813 nindy_create_inferior (execfile, args, env)
814      char *execfile;
815      char *args;
816      char **env;
817 {
818   int entry_pt;
819   int pid;
820
821   if (args && *args)
822     error ("Can't pass arguments to remote NINDY process");
823
824   if (execfile == 0 || exec_bfd == 0)
825     error ("No exec file specified");
826
827   entry_pt = (int) bfd_get_start_address (exec_bfd);
828
829   pid = 42;
830
831 #ifdef CREATE_INFERIOR_HOOK
832   CREATE_INFERIOR_HOOK (pid);
833 #endif  
834
835 /* The "process" (board) is already stopped awaiting our commands, and
836    the program is already downloaded.  We just set its PC and go.  */
837
838   inferior_pid = pid;           /* Needed for wait_for_inferior below */
839
840   clear_proceed_status ();
841
842   /* Tell wait_for_inferior that we've started a new process.  */
843   init_wait_for_inferior ();
844
845   /* Set up the "saved terminal modes" of the inferior
846      based on what modes we are starting it with.  */
847   target_terminal_init ();
848
849   /* Install inferior's terminal modes.  */
850   target_terminal_inferior ();
851
852   /* insert_step_breakpoint ();  FIXME, do we need this?  */
853   proceed ((CORE_ADDR)entry_pt, -1, 0);         /* Let 'er rip... */
854 }
855
856 static void
857 reset_command(args, from_tty)
858      char *args;
859      int from_tty;
860 {
861         if ( !nindy_fd ){
862             error( "No target system to reset -- use 'target nindy' command.");
863         }
864         if ( query("Really reset the target system?",0,0) ){
865                 send_break( nindy_fd );
866                 tty_flush( nindy_fd );
867         }
868 }
869
870 void
871 nindy_kill (args, from_tty)
872      char *args;
873      int from_tty;
874 {
875   return;               /* Ignore attempts to kill target system */
876 }
877
878 /* Clean up when a program exits.
879
880    The program actually lives on in the remote processor's RAM, and may be
881    run again without a download.  Don't leave it full of breakpoint
882    instructions.  */
883
884 void
885 nindy_mourn_inferior ()
886 {
887   remove_breakpoints ();
888   unpush_target (&nindy_ops);
889   generic_mourn_inferior ();    /* Do all the proper things now */
890 }
891 \f
892 /* This routine is run as a hook, just before the main command loop is
893    entered.  If gdb is configured for the i960, but has not had its
894    nindy target specified yet, this will loop prompting the user to do so.
895
896    Unlike the loop provided by Intel, we actually let the user get out
897    of this with a RETURN.  This is useful when e.g. simply examining
898    an i960 object file on the host system.  */
899
900 void
901 nindy_before_main_loop ()
902 {
903   char ttyname[100];
904   char *p, *p2;
905
906   setjmp(to_top_level);
907   while (current_target != &nindy_ops) { /* remote tty not specified yet */
908         if ( instream == stdin ){
909                 printf("\nAttach /dev/ttyNN -- specify NN, or \"quit\" to quit:  ");
910                 fflush( stdout );
911         }
912         fgets( ttyname, sizeof(ttyname)-1, stdin );
913
914         /* Strip leading and trailing whitespace */
915         for ( p = ttyname; isspace(*p); p++ ){
916                 ;
917         }
918         if ( *p == '\0' ){
919                 return;         /* User just hit spaces or return, wants out */
920         }
921         for ( p2= p; !isspace(*p2) && (*p2 != '\0'); p2++ ){
922                 ;
923         }
924         *p2= '\0';
925         if ( STREQ("quit",p) ){
926                 exit(1);
927         }
928
929         nindy_open( p, 1 );
930
931         /* Now that we have a tty open for talking to the remote machine,
932            download the executable file if one was specified.  */
933         if ( !setjmp(to_top_level) && exec_bfd ) {
934               target_load (bfd_get_filename (exec_bfd), 1);
935         }
936   }
937 }
938 \f
939 /* Define the target subroutine names */
940
941 struct target_ops nindy_ops = {
942         "nindy", "Remote serial target in i960 NINDY-specific protocol",
943         "Use a remote i960 system running NINDY connected by a serial line.\n\
944 Specify the name of the device the serial line is connected to.\n\
945 The speed (baud rate), whether to use the old NINDY protocol,\n\
946 and whether to send a break on startup, are controlled by options\n\
947 specified when you started GDB.",
948         nindy_open, nindy_close,
949         0,
950         nindy_detach,
951         nindy_resume,
952         nindy_wait,
953         nindy_fetch_registers, nindy_store_registers,
954         nindy_prepare_to_store,
955         nindy_xfer_inferior_memory, nindy_files_info,
956         0, 0, /* insert_breakpoint, remove_breakpoint, */
957         0, 0, 0, 0, 0,  /* Terminal crud */
958         nindy_kill,
959         nindy_load,
960         0, /* lookup_symbol */
961         nindy_create_inferior,
962         nindy_mourn_inferior,
963         0,              /* can_run */
964         0, /* notice_signals */
965         process_stratum, 0, /* next */
966         1, 1, 1, 1, 1,  /* all mem, mem, stack, regs, exec */
967         0, 0,                   /* Section pointers */
968         OPS_MAGIC,              /* Always the last thing */
969 };
970
971 void
972 _initialize_nindy ()
973 {
974   add_target (&nindy_ops);
975   add_com ("reset", class_obscure, reset_command,
976            "Send a 'break' to the remote target system.\n\
977 Only useful if the target has been equipped with a circuit\n\
978 to perform a hard reset when a break is detected.");
979 }