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