* xm-sun3os4.h, xm-sun4os4.h: Enable HAVE_MMAP.
[deliverable/binutils-gdb.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 }
This page took 0.056196 seconds and 4 git commands to generate.