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