fix stabs.texinfo xref bugs
[deliverable/binutils-gdb.git] / gdb / remote-nindy.c
CommitLineData
dd3b648e 1/* Memory-access and commands for remote NINDY process, for GDB.
58bcc08c 2 Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
dd3b648e
RP
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
d747e0af 98#include "defs.h"
dd3b648e
RP
99#include <signal.h>
100#include <sys/types.h>
101#include <setjmp.h>
102
dd3b648e
RP
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
120extern int unlink();
121extern char *getenv();
122extern char *mktemp();
123
124extern char *coffstrip();
dd3b648e
RP
125extern void generic_mourn_inferior ();
126
127extern struct target_ops nindy_ops;
128extern jmp_buf to_top_level;
129extern FILE *instream;
9fa28378 130extern struct ext_format ext_format_i960; /* i960-tdep.c */
dd3b648e
RP
131
132extern char ninStopWhy ();
133
134int nindy_initial_brk; /* nonzero if want to send an initial BREAK to nindy */
135int nindy_old_protocol; /* nonzero if want to use old protocol */
136char *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
143int nindy_fd = 0; /* Descriptor for I/O to NINDY */
144static int have_regs = 0; /* 1 iff regs read since i960 last halted */
145static int regs_changed = 0; /* 1 iff regs were modified since last read */
146
147extern char *exists();
e4db3f3e
JG
148
149static void
150dcache_flush (), dcache_poke (), dcache_init();
151
152static int
153dcache_fetch ();
154
155static void
156nindy_fetch_registers PARAMS ((int));
157
158static void
159nindy_store_registers PARAMS ((int));
dd3b648e
RP
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
168static TTY_STRUCT orig_tty; /* TTY attributes before entering passthrough */
169
170static void
171restore_tty()
172{
173 ioctl( 0, TIOCSETN, &orig_tty );
174}
175
176
177/* Recover from ^Z or ^C while remote process is running */
178
179static void (*old_ctrlc)(); /* Signal handlers before entering passthrough */
180
181#ifdef SIGTSTP
182static void (*old_ctrlz)();
183#endif
184
185static
186#ifdef USG
187void
188#endif
189cleanup()
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
201static char *savename;
202
203static void
204nindy_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) */
220void
221nindy_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
f2fc6e7a
JK
229 target_preopen (from_tty);
230
dd3b648e
RP
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
256static void
257nindy_detach (name, from_tty)
258 char *name;
259 int from_tty;
260{
dd3b648e
RP
261 if (name)
262 error ("Too many arguments");
263 pop_target ();
264}
265
266static void
267nindy_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
284static void
285nindy_load( filename, from_tty )
286 char *filename;
287 int from_tty;
288{
0256270d
KR
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;
dd3b648e 299 }
0256270d
KR
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);
dd3b648e
RP
322}
323
dd3b648e
RP
324/* Return the number of characters in the buffer before the first DLE character.
325 */
326
327static
328int
329non_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
345void
346nindy_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 ){
df86eb44 354 nindy_store_registers (-1);
dd3b648e
RP
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
e4db3f3e 368static int
dd3b648e
RP
369nindy_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 */
df86eb44
JG
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);
dd3b648e
RP
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 }
e4db3f3e 472 return inferior_pid;
dd3b648e
RP
473}
474
475/* Read the remote registers into the block REGS. */
476
477/* This is the block that ninRegsGet and ninRegsPut handles. */
478struct 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
120f867e 487static void
dd3b648e
RP
488nindy_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 */
9fa28378 509 double_to_ieee_extended (&ext_format_i960, &dub,
dd3b648e
RP
510 &registers[REGISTER_BYTE (regnum)]);
511 }
512
513 registers_fetched ();
dd3b648e
RP
514}
515
516static void
517nindy_prepare_to_store()
518{
4ddd278f
JG
519 /* Fetch all regs if they aren't already here. */
520 read_register_bytes (0, NULL, REGISTER_BYTES);
dd3b648e
RP
521}
522
120f867e 523static void
dd3b648e
RP
524nindy_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);
df86eb44 536 /* Float regs. Only works on IEEE_FLOAT hosts. FIXME! */
dd3b648e 537 for (regnum = FP0_REGNUM; regnum < FP0_REGNUM + 4; regnum++) {
9fa28378 538 ieee_extended_to_double (&ext_format_i960,
dd3b648e
RP
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. */
df86eb44 544 dub = unpack_double (builtin_type_double, (char *)&dub, &inv);
dd3b648e
RP
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--;
dd3b648e
RP
553}
554
555/* Read a word from remote address ADDR and return it.
556 * This goes through the data cache.
557 */
558int
559nindy_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
568void
569nindy_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
584int
8f1f2a72 585nindy_xfer_inferior_memory(memaddr, myaddr, len, write, target)
dd3b648e
RP
586 CORE_ADDR memaddr;
587 char *myaddr;
588 int len;
589 int write;
8f1f2a72 590 struct target_ops *target; /* ignored */
dd3b648e
RP
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
656struct dcache_block {
657 struct dcache_block *next, *last;
658 unsigned int addr; /* Address for which data is recorded. */
659 int data[4];
660};
661
662struct dcache_block dcache_free, dcache_valid;
663
664/* Free all the data cache blocks, thus discarding all cached data. */
665static
666void
667dcache_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 */
682static
683struct dcache_block *
684dcache_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. */
704static
705int
706dcache_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...). */
721static
722struct dcache_block *
723dcache_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. */
743static
744int
745dcache_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. */
765static void
766dcache_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. */
795struct dcache_block the_cache[DCACHE_SIZE];
796
797/* Initialize the data cache. */
798static void
799dcache_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
812static void
813nindy_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
dd3b648e
RP
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
dd3b648e
RP
852 /* insert_step_breakpoint (); FIXME, do we need this? */
853 proceed ((CORE_ADDR)entry_pt, -1, 0); /* Let 'er rip... */
854}
855
856static void
857reset_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
870void
871nindy_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
884void
885nindy_mourn_inferior ()
886{
887 remove_breakpoints ();
888 generic_mourn_inferior (); /* Do all the proper things now */
889}
890\f
891/* This routine is run as a hook, just before the main command loop is
892 entered. If gdb is configured for the i960, but has not had its
893 nindy target specified yet, this will loop prompting the user to do so.
894
895 Unlike the loop provided by Intel, we actually let the user get out
896 of this with a RETURN. This is useful when e.g. simply examining
897 an i960 object file on the host system. */
898
df86eb44 899void
dd3b648e
RP
900nindy_before_main_loop ()
901{
902 char ttyname[100];
903 char *p, *p2;
904
905 setjmp(to_top_level);
906 while (current_target != &nindy_ops) { /* remote tty not specified yet */
907 if ( instream == stdin ){
908 printf("\nAttach /dev/ttyNN -- specify NN, or \"quit\" to quit: ");
909 fflush( stdout );
910 }
911 fgets( ttyname, sizeof(ttyname)-1, stdin );
912
913 /* Strip leading and trailing whitespace */
914 for ( p = ttyname; isspace(*p); p++ ){
915 ;
916 }
917 if ( *p == '\0' ){
918 return; /* User just hit spaces or return, wants out */
919 }
920 for ( p2= p; !isspace(*p2) && (*p2 != '\0'); p2++ ){
921 ;
922 }
923 *p2= '\0';
2e4964ad 924 if ( STREQ("quit",p) ){
dd3b648e
RP
925 exit(1);
926 }
927
928 nindy_open( p, 1 );
929
930 /* Now that we have a tty open for talking to the remote machine,
931 download the executable file if one was specified. */
932 if ( !setjmp(to_top_level) && exec_bfd ) {
933 target_load (bfd_get_filename (exec_bfd), 1);
934 }
935 }
936}
937\f
938/* Define the target subroutine names */
939
940struct target_ops nindy_ops = {
941 "nindy", "Remote serial target in i960 NINDY-specific protocol",
f2fc6e7a
JK
942 "Use a remote i960 system running NINDY connected by a serial line.\n\
943Specify the name of the device the serial line is connected to.\n\
944The speed (baud rate), whether to use the old NINDY protocol,\n\
945and whether to send a break on startup, are controlled by options\n\
946specified when you started GDB.",
dd3b648e 947 nindy_open, nindy_close,
58bcc08c
JG
948 0,
949 nindy_detach,
950 nindy_resume,
951 nindy_wait,
dd3b648e 952 nindy_fetch_registers, nindy_store_registers,
a03d4f8e 953 nindy_prepare_to_store,
dd3b648e
RP
954 nindy_xfer_inferior_memory, nindy_files_info,
955 0, 0, /* insert_breakpoint, remove_breakpoint, */
956 0, 0, 0, 0, 0, /* Terminal crud */
957 nindy_kill,
8f1f2a72 958 nindy_load,
dd3b648e
RP
959 0, /* lookup_symbol */
960 nindy_create_inferior,
961 nindy_mourn_inferior,
0256270d
KR
962 0, /* can_run */
963 0, /* notice_signals */
dd3b648e
RP
964 process_stratum, 0, /* next */
965 1, 1, 1, 1, 1, /* all mem, mem, stack, regs, exec */
8f1f2a72 966 0, 0, /* Section pointers */
dd3b648e
RP
967 OPS_MAGIC, /* Always the last thing */
968};
969
970void
971_initialize_nindy ()
972{
973 add_target (&nindy_ops);
974 add_com ("reset", class_obscure, reset_command,
975 "Send a 'break' to the remote target system.\n\
976Only useful if the target has been equipped with a circuit\n\
977to perform a hard reset when a break is detected.");
978}
This page took 0.131476 seconds and 4 git commands to generate.