]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/nindy-share/nindy.c
Initial creation of sourceware repository
[thirdparty/binutils-gdb.git] / gdb / nindy-share / nindy.c
1 /* This file is part of GDB.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
16
17 /* This started out life as code shared between the nindy monitor and
18 GDB. For various reasons, this is no longer true. Eventually, it
19 probably should be merged into remote-nindy.c. */
20
21 /******************************************************************************
22 *
23 * NINDY INTERFACE ROUTINES
24 *
25 * The caller of these routines should be aware that:
26 *
27 * (1) ninConnect() should be called to open communications with the
28 * remote NINDY board before any of the other routines are invoked.
29 *
30 * (2) almost all interactions are driven by the host: nindy sends information
31 * in response to host commands.
32 *
33 * (3) the lone exception to (2) is the single character DLE (^P, 0x10).
34 * Receipt of a DLE from NINDY indicates that the application program
35 * running under NINDY has stopped execution and that NINDY is now
36 * available to talk to the host (all other communication received after
37 * the application has been started should be presumed to come from the
38 * application and should be passed on by the host to stdout).
39 *
40 * (4) the reason the application program stopped can be determined with the
41 * ninStopWhy() function. There are three classes of stop reasons:
42 *
43 * (a) the application has terminated execution.
44 * The host should take appropriate action.
45 *
46 * (b) the application had a fault or trace event.
47 * The host should take appropriate action.
48 *
49 * (c) the application wishes to make a service request (srq) of the host;
50 * e.g., to open/close a file, read/write a file, etc. The ninSrq()
51 * function should be called to determine the nature of the request
52 * and process it.
53 */
54
55 #include <stdio.h>
56 #include "defs.h"
57 #include "serial.h"
58 #ifdef ANSI_PROTOTYPES
59 #include <stdarg.h>
60 #else
61 #include <varargs.h>
62 #endif
63
64 #if !defined (HAVE_TERMIOS) && !defined (HAVE_TERMIO) && !defined (HAVE_SGTTY)
65 #define HAVE_SGTTY
66 #endif
67
68 #ifdef HAVE_SGTTY
69 #include <sys/ioctl.h>
70 #endif
71
72 #include <sys/types.h> /* Needed by file.h on Sys V */
73 #include <sys/file.h>
74 #include <signal.h>
75 #include <sys/stat.h>
76
77 #if 0
78 #include "ttycntl.h"
79 #endif
80 #include "block_io.h"
81 #include "wait.h"
82 #include "env.h"
83
84 #define DLE 0x10 /* ^P */
85 #define XON 0x11 /* ^Q */
86 #define XOFF 0x13 /* ^S */
87 #define ESC 0x1b
88
89 #define TIMEOUT -1
90
91 int quiet = 0; /* 1 => stifle unnecessary messages */
92 serial_t nindy_serial;
93
94 static int old_nindy = 0; /* 1 => use old (hex) communication protocol */
95 static ninStrGet();
96 \f
97 /****************************
98 * *
99 * MISCELLANEOUS UTILTIES *
100 * *
101 ****************************/
102
103 /******************************************************************************
104 * say:
105 * This is a printf that takes at most two arguments (in addition to the
106 * format string) and that outputs nothing if verbose output has been
107 * suppressed.
108 *****************************************************************************/
109
110 /* VARARGS */
111 static void
112 #ifdef ANSI_PROTOTYPES
113 say (char *fmt, ...)
114 #else
115 say (va_alist)
116 va_dcl
117 #endif
118 {
119 va_list args;
120 #ifdef ANSI_PROTOTYPES
121 va_start(args, fmt);
122 #else
123 char *fmt;
124
125 va_start (args);
126 fmt = va_arg (args, char *);
127 #endif
128
129 if (!quiet)
130 {
131 vfprintf_unfiltered (gdb_stdout, fmt, args);
132 gdb_flush (gdb_stdout);
133 }
134 va_end (args);
135 }
136
137 /******************************************************************************
138 * exists:
139 * Creates a full pathname by concatenating up to three name components
140 * onto a specified base name; optionally looks up the base name as a
141 * runtime environment variable; and checks to see if the file or
142 * directory specified by the pathname actually exists.
143 *
144 * Returns: the full pathname if it exists, NULL otherwise.
145 * (returned pathname is in malloc'd memory and must be freed
146 * by caller).
147 *****************************************************************************/
148 static char *
149 exists( base, c1, c2, c3, env )
150 char *base; /* Base directory of path */
151 char *c1, *c2, *c3; /* Components (subdirectories and/or file name) to be
152 * appended onto the base directory name. One or
153 * more may be omitted by passing NULL pointers.
154 */
155 int env; /* If 1, '*base' is the name of an environment variable
156 * to be examined for the base directory name;
157 * otherwise, '*base' is the actual name of the
158 * base directory.
159 */
160 {
161 struct stat buf;/* For call to 'stat' -- never examined */
162 char *path; /* Pointer to full pathname (malloc'd memory) */
163 int len; /* Length of full pathname (incl. terminator) */
164 extern char *getenv();
165
166
167 if ( env ){
168 base = getenv( base );
169 if ( base == NULL ){
170 return NULL;
171 }
172 }
173
174 len = strlen(base) + 4;
175 /* +4 for terminator and "/" before each component */
176 if ( c1 != NULL ){
177 len += strlen(c1);
178 }
179 if ( c2 != NULL ){
180 len += strlen(c2);
181 }
182 if ( c3 != NULL ){
183 len += strlen(c3);
184 }
185
186 path = xmalloc (len);
187
188 strcpy( path, base );
189 if ( c1 != NULL ){
190 strcat( path, "/" );
191 strcat( path, c1 );
192 if ( c2 != NULL ){
193 strcat( path, "/" );
194 strcat( path, c2 );
195 if ( c3 != NULL ){
196 strcat( path, "/" );
197 strcat( path, c3 );
198 }
199 }
200 }
201
202 if ( stat(path,&buf) != 0 ){
203 free( path );
204 path = NULL;
205 }
206 return path;
207 }
208 \f
209 /*****************************
210 * *
211 * LOW-LEVEL COMMUNICATION *
212 * *
213 *****************************/
214
215 /* Read *exactly* N characters from the NINDY tty, and put them in
216 *BUF. Translate escape sequences into single characters, counting
217 each such sequence as 1 character.
218
219 An escape sequence consists of ESC and a following character. The
220 ESC is discarded and the other character gets bit 0x40 cleared --
221 thus ESC P == ^P, ESC S == ^S, ESC [ == ESC, etc.
222
223 Return 1 if successful, 0 if more than TIMEOUT seconds pass without
224 any input. */
225
226 static int
227 rdnin (buf,n,timeout)
228 unsigned char * buf; /* Where to place characters read */
229 int n; /* Number of characters to read */
230 int timeout; /* Timeout, in seconds */
231 {
232 int escape_seen; /* 1 => last character of a read was an ESC */
233 int c;
234
235 escape_seen = 0;
236 while (n)
237 {
238 c = SERIAL_READCHAR (nindy_serial, timeout);
239 switch (c)
240 {
241 case SERIAL_ERROR:
242 case SERIAL_TIMEOUT:
243 case SERIAL_EOF:
244 return 0;
245
246 case ESC:
247 escape_seen = 1;
248 break;
249
250 default:
251 if (escape_seen)
252 {
253 escape_seen = 0;
254 c &= ~0x40;
255 }
256 *buf++ = c;
257 --n;
258 break;
259 }
260 }
261 return 1;
262 }
263
264
265 /******************************************************************************
266 * getpkt:
267 * Read a packet from a remote NINDY, with error checking, into the
268 * indicated buffer.
269 *
270 * Return packet status byte on success, TIMEOUT on failure.
271 ******************************************************************************/
272 static
273 int
274 getpkt(buf)
275 unsigned char *buf;
276 {
277 int i;
278 unsigned char hdr[3]; /* Packet header:
279 * hdr[0] = low byte of message length
280 * hdr[1] = high byte of message length
281 * hdr[2] = message status
282 */
283 int cnt; /* Message length (status byte + data) */
284 unsigned char cs_calc; /* Checksum calculated */
285 unsigned char cs_recv; /* Checksum received */
286 static char errfmt[] =
287 "Bad checksum (recv=0x%02x; calc=0x%02x); retrying\r\n";
288
289 while (1){
290 if ( !rdnin(hdr,3,5) ){
291 return TIMEOUT;
292 }
293 cnt = (hdr[1]<<8) + hdr[0] - 1;
294 /* -1 for status byte (already read) */
295
296 /* Caller's buffer may only be big enough for message body,
297 * without status byte and checksum, so make sure to read
298 * checksum into a separate buffer.
299 */
300 if ( !rdnin(buf,cnt,5) || !rdnin(&cs_recv,1,5) ){
301 return TIMEOUT;
302 }
303
304 /* Calculate checksum
305 */
306 cs_calc = hdr[0] + hdr[1] + hdr[2];
307 for ( i = 0; i < cnt; i++ ){
308 cs_calc += buf[i];
309 }
310 if ( cs_calc == cs_recv ){
311 SERIAL_WRITE (nindy_serial, "+", 1);
312 return hdr[2];
313 }
314
315 /* Bad checksum: report, send NAK, and re-receive
316 */
317 fprintf(stderr, errfmt, cs_recv, cs_calc );
318 SERIAL_WRITE (nindy_serial, "-", 1);
319 }
320 }
321
322
323 /******************************************************************************
324 * putpkt:
325 * Send a packet to NINDY, checksumming it and converting special
326 * characters to escape sequences.
327 ******************************************************************************/
328
329 /* This macro puts the character 'c' into the buffer pointed at by 'p',
330 * and increments the pointer. If 'c' is one of the 4 special characters
331 * in the transmission protocol, it is converted into a 2-character
332 * escape sequence.
333 */
334 #define PUTBUF(c,p) \
335 if ( c == DLE || c == ESC || c == XON || c == XOFF ){ \
336 *p++ = ESC; \
337 *p++ = c | 0x40; \
338 } else { \
339 *p++ = c; \
340 }
341
342 static
343 putpkt( msg, len )
344 unsigned char *msg; /* Command to be sent, without lead ^P (\020) or checksum */
345 int len; /* Number of bytes in message */
346 {
347 static char *buf = NULL;/* Local buffer -- build packet here */
348 static int maxbuf = 0; /* Current length of buffer */
349 unsigned char ack; /* Response received from NINDY */
350 unsigned char checksum; /* Packet checksum */
351 char *p; /* Pointer into buffer */
352 int lenhi, lenlo; /* High and low bytes of message length */
353 int i;
354
355
356 /* Make sure local buffer is big enough. Must include space for
357 * packet length, message body, and checksum. And in the worst
358 * case, each character would expand into a 2-character escape
359 * sequence.
360 */
361 if ( maxbuf < ((2*len)+10) ){
362 if ( buf ){
363 free( buf );
364 }
365 buf = xmalloc( maxbuf=((2*len)+10) );
366 }
367
368 /* Attention, NINDY!
369 */
370 SERIAL_WRITE (nindy_serial, "\020", 1);
371
372
373 lenlo = len & 0xff;
374 lenhi = (len>>8) & 0xff;
375 checksum = lenlo + lenhi;
376 p = buf;
377
378 PUTBUF( lenlo, p );
379 PUTBUF( lenhi, p );
380
381 for ( i=0; i<len; i++ ){
382 PUTBUF( msg[i], p );
383 checksum += msg[i];
384 }
385
386 PUTBUF( checksum, p );
387
388 /* Send checksummed message over and over until we get a positive ack
389 */
390 SERIAL_WRITE (nindy_serial, buf, p - buf);
391 while (1){
392 if ( !rdnin(&ack,1,5) ){
393 /* timed out */
394 fprintf(stderr,"ACK timed out; resending\r\n");
395 /* Attention, NINDY! */
396 SERIAL_WRITE (nindy_serial, "\020", 1);
397 SERIAL_WRITE (nindy_serial, buf, p - buf);
398 } else if ( ack == '+' ){
399 return;
400 } else if ( ack == '-' ){
401 fprintf( stderr, "Remote NAK; resending\r\n" );
402 SERIAL_WRITE (nindy_serial, buf, p - buf);
403 } else {
404 fprintf( stderr, "Bad ACK, ignored: <%c>\r\n", ack );
405 }
406 }
407 }
408
409
410
411 /******************************************************************************
412 * send:
413 * Send a message to a remote NINDY. Check message status byte
414 * for error responses. If no error, return NINDY reponse (if any).
415 ******************************************************************************/
416 static
417 send( out, len, in )
418 unsigned char *out; /* Message to be sent to NINDY */
419 int len; /* Number of meaningful bytes in out buffer */
420 unsigned char *in; /* Where to put response received from NINDY */
421 {
422 char *fmt;
423 int status;
424 static char *errmsg[] = {
425 "", /* 0 */
426 "Buffer overflow", /* 1 */
427 "Unknown command", /* 2 */
428 "Wrong amount of data to load register(s)", /* 3 */
429 "Missing command argument(s)", /* 4 */
430 "Odd number of digits sent to load memory", /* 5 */
431 "Unknown register name", /* 6 */
432 "No such memory segment", /* 7 */
433 "No breakpoint available", /* 8 */
434 "Can't set requested baud rate", /* 9 */
435 };
436 # define NUMERRS ( sizeof(errmsg) / sizeof(errmsg[0]) )
437
438 static char err1[] = "Unknown error response from NINDY: #%d\r\n";
439 static char err2[] = "Error response #%d from NINDY: %s\r\n";
440
441 while (1){
442 putpkt(out,len);
443 status = getpkt(in);
444 if ( status == TIMEOUT ){
445 fprintf( stderr, "Response timed out; resending\r\n" );
446 } else {
447 break;
448 }
449 }
450
451 if ( status ){
452 fmt = status > NUMERRS ? err1 : err2;
453 fprintf( stderr, fmt, status, errmsg[status] );
454 abort();
455 }
456 }
457 \f
458 /************************
459 * *
460 * BAUD RATE ROUTINES *
461 * *
462 ************************/
463
464 /* Table of baudrates known to be acceptable to NINDY. Each baud rate
465 * appears both as character string and as a Unix baud rate constant.
466 */
467 struct baudrate {
468 char *string;
469 int rate;
470 };
471
472 static struct baudrate baudtab[] = {
473 "1200", 1200,
474 "2400", 2400,
475 "4800", 4800,
476 "9600", 9600,
477 "19200", 19200,
478 "38400", 38400,
479 NULL, 0 /* End of table */
480 };
481
482 /******************************************************************************
483 * parse_baudrate:
484 * Look up the passed baud rate in the baudrate table. If found, change
485 * our internal record of the current baud rate, but don't do anything
486 * about the tty just now.
487 *
488 * Return pointer to baudrate structure on success, NULL on failure.
489 ******************************************************************************/
490 static
491 struct baudrate *
492 parse_baudrate(s)
493 char *s; /* Desired baud rate, as an ASCII (decimal) string */
494 {
495 int i;
496
497 for ( i=0; baudtab[i].string != NULL; i++ ){
498 if ( !strcmp(baudtab[i].string,s) ){
499 return &baudtab[i];
500 }
501 }
502 return NULL;
503 }
504
505 /******************************************************************************
506 * try_baudrate:
507 * Try speaking to NINDY via the specified file descriptor at the
508 * specified baudrate. Assume success if we can send an empty command
509 * with a bogus checksum and receive a NAK (response of '-') back within
510 * one second.
511 *
512 * Return 1 on success, 0 on failure.
513 ***************************************************************************/
514
515 static int
516 try_baudrate (serial, brp)
517 serial_t serial;
518 struct baudrate *brp;
519 {
520 unsigned char c;
521
522 /* Set specified baud rate and flush all pending input */
523 SERIAL_SETBAUDRATE (serial, brp->rate);
524 tty_flush (serial);
525
526 /* Send empty command with bad checksum, hope for NAK ('-') response */
527 SERIAL_WRITE (serial, "\020\0\0\001", 4);
528
529 /* Anything but a quick '-', including error, eof, or timeout, means that
530 this baudrate doesn't work. */
531 return SERIAL_READCHAR (serial, 1) == '-';
532 }
533
534 /******************************************************************************
535 * autobaud:
536 * Get NINDY talking over the specified file descriptor at the specified
537 * baud rate. First see if NINDY's already talking at 'baudrate'. If
538 * not, run through all the legal baudrates in 'baudtab' until one works,
539 * and then tell NINDY to talk at 'baudrate' instead.
540 ******************************************************************************/
541 static
542 autobaud( serial, brp )
543 serial_t serial;
544 struct baudrate *brp;
545 {
546 int i;
547 int failures;
548
549 say("NINDY at wrong baud rate? Trying to autobaud...\n");
550 failures = i = 0;
551 while (1)
552 {
553 say( "\r%s... ", baudtab[i].string );
554 if (try_baudrate(serial, &baudtab[i]))
555 {
556 break;
557 }
558 if (baudtab[++i].string == NULL)
559 {
560 /* End of table -- wraparound */
561 i = 0;
562 if ( failures++ )
563 {
564 say("\nAutobaud failed again. Giving up.\n");
565 exit(1);
566 }
567 else
568 {
569 say("\nAutobaud failed. Trying again...\n");
570 }
571 }
572 }
573
574 /* Found NINDY's current baud rate; now change it. */
575 say("Changing NINDY baudrate to %s\n", brp->string);
576 ninBaud (brp->string);
577
578 /* Change our baud rate back to rate to which we just set NINDY. */
579 SERIAL_SETBAUDRATE (serial, brp->rate);
580 }
581 \f
582 /**********************************
583 * *
584 * NINDY INTERFACE ROUTINES *
585 * *
586 * ninConnect *MUST* be the first *
587 * one of these routines called. *
588 **********************************/
589
590
591 /******************************************************************************
592 * ninBaud:
593 * Ask NINDY to change the baud rate on its serial port.
594 * Assumes we know the baud rate at which NINDY's currently talking.
595 ******************************************************************************/
596 ninBaud( baudrate )
597 char *baudrate; /* Desired baud rate, as a string of ASCII decimal
598 * digits.
599 */
600 {
601 unsigned char msg[100];
602
603 tty_flush (nindy_serial);
604
605 if (old_nindy)
606 {
607 char *p; /* Pointer into buffer */
608 unsigned char csum; /* Calculated checksum */
609
610 /* Can't use putpkt() because after the baudrate change NINDY's
611 ack/nak will look like gibberish. */
612
613 for (p=baudrate, csum=020+'z'; *p; p++)
614 {
615 csum += *p;
616 }
617 sprintf (msg, "\020z%s#%02x", baudrate, csum);
618 SERIAL_WRITE (nindy_serial, msg, strlen (msg));
619 }
620 else
621 {
622 /* Can't use "send" because NINDY reply will be unreadable after
623 baud rate change. */
624 sprintf( msg, "z%s", baudrate );
625 putpkt( msg, strlen(msg)+1 ); /* "+1" to send terminator too */
626 }
627 }
628
629 /******************************************************************************
630 * ninBptDel:
631 * Ask NINDY to delete the specified type of *hardware* breakpoint at
632 * the specified address. If the 'addr' is -1, all breakpoints of
633 * the specified type are deleted.
634 ***************************************************************************/
635 ninBptDel( addr, type )
636 long addr; /* Address in 960 memory */
637 char type; /* 'd' => data bkpt, 'i' => instruction breakpoint */
638 {
639 unsigned char buf[10];
640
641 if ( old_nindy ){
642 OninBptDel( addr, type == 'd' ? 1 : 0 );
643 return;
644 }
645
646 buf[0] = 'b';
647 buf[1] = type;
648
649 if ( addr == -1 ){
650 send( buf, 2, NULL );
651 } else {
652 store_unsigned_integer (&buf[2], 4, addr);
653 send( buf, 6, NULL );
654 }
655 }
656
657
658 /******************************************************************************
659 * ninBptSet:
660 * Ask NINDY to set the specified type of *hardware* breakpoint at
661 * the specified address.
662 ******************************************************************************/
663 ninBptSet( addr, type )
664 long addr; /* Address in 960 memory */
665 char type; /* 'd' => data bkpt, 'i' => instruction breakpoint */
666 {
667 unsigned char buf[10];
668
669 if ( old_nindy ){
670 OninBptSet( addr, type == 'd' ? 1 : 0 );
671 return;
672 }
673
674
675 buf[0] = 'B';
676 buf[1] = type;
677 store_unsigned_integer (&buf[2], 4, addr);
678 send( buf, 6, NULL );
679 }
680
681
682 /******************************************************************************
683 * ninConnect:
684 * Open the specified tty. Get communications working at the specified
685 * baud rate. Flush any pending I/O on the tty.
686 *
687 * Return the file descriptor, or -1 on failure.
688 ******************************************************************************/
689 int
690 ninConnect( name, baudrate, brk, silent, old_protocol )
691 char *name; /* "/dev/ttyXX" to be opened */
692 char *baudrate;/* baud rate: a string of ascii decimal digits (eg,"9600")*/
693 int brk; /* 1 => send break to tty first thing after opening it*/
694 int silent; /* 1 => stifle unnecessary messages when talking to
695 * this tty.
696 */
697 int old_protocol;
698 {
699 int i;
700 char *p;
701 struct baudrate *brp;
702
703 /* We will try each of the following paths when trying to open the tty
704 */
705 static char *prefix[] = { "", "/dev/", "/dev/tty", NULL };
706
707 if ( old_protocol ){
708 old_nindy = 1;
709 }
710
711 quiet = silent; /* Make global to this file */
712
713 for ( i=0; prefix[i] != NULL; i++ ){
714 p = xmalloc(strlen(prefix[i]) + strlen(name) + 1 );
715 strcpy( p, prefix[i] );
716 strcat( p, name );
717 nindy_serial = SERIAL_OPEN (p);
718 if (nindy_serial != NULL) {
719 #ifdef TIOCEXCL
720 /* Exclusive use mode (hp9000 does not support it) */
721 ioctl(nindy_serial->fd,TIOCEXCL,NULL);
722 #endif
723 SERIAL_RAW (nindy_serial);
724
725 if (brk)
726 {
727 SERIAL_SEND_BREAK (nindy_serial);
728 }
729
730 brp = parse_baudrate( baudrate );
731 if ( brp == NULL ){
732 say("Illegal baudrate %s ignored; using 9600\n",
733 baudrate);
734 brp = parse_baudrate( "9600" );
735 }
736
737 if ( !try_baudrate(nindy_serial, brp) ){
738 autobaud(nindy_serial, brp);
739 }
740 tty_flush (nindy_serial);
741 say( "Connected to %s\n", p );
742 free(p);
743 break;
744 }
745 free(p);
746 }
747 return 0;
748 }
749
750 #if 0
751
752 /* Currently unused; shouldn't we be doing this on target_kill and
753 perhaps target_mourn? FIXME. */
754
755 /******************************************************************************
756 * ninGdbExit:
757 * Ask NINDY to leave GDB mode and print a NINDY prompt.
758 ****************************************************************************/
759 ninGdbExit()
760 {
761 if ( old_nindy ){
762 OninGdbExit();
763 return;
764 }
765 putpkt((unsigned char *) "E", 1 );
766 }
767 #endif
768
769 /******************************************************************************
770 * ninGo:
771 * Ask NINDY to start or continue execution of an application program
772 * in it's memory at the current ip.
773 ******************************************************************************/
774 ninGo( step_flag )
775 int step_flag; /* 1 => run in single-step mode */
776 {
777 if ( old_nindy ){
778 OninGo( step_flag );
779 return;
780 }
781 putpkt((unsigned char *) (step_flag ? "s" : "c"), 1 );
782 }
783
784
785 /******************************************************************************
786 * ninMemGet:
787 * Read a string of bytes from NINDY's address space (960 memory).
788 ******************************************************************************/
789 int
790 ninMemGet(ninaddr, hostaddr, len)
791 long ninaddr; /* Source address, in the 960 memory space */
792 unsigned char *hostaddr; /* Destination address, in our memory space */
793 int len; /* Number of bytes to read */
794 {
795 unsigned char buf[BUFSIZE+20];
796 int cnt; /* Number of bytes in next transfer */
797 int origlen = len;
798
799 if ( old_nindy ){
800 OninMemGet(ninaddr, hostaddr, len);
801 return;
802 }
803
804 for ( ; len > 0; len -= BUFSIZE ){
805 cnt = len > BUFSIZE ? BUFSIZE : len;
806
807 buf[0] = 'm';
808 store_unsigned_integer (&buf[1], 4, ninaddr);
809 buf[5] = cnt & 0xff;
810 buf[6] = (cnt>>8) & 0xff;
811
812 send( buf, 7, hostaddr );
813
814 ninaddr += cnt;
815 hostaddr += cnt;
816 }
817 return origlen;
818 }
819
820
821 /******************************************************************************
822 * ninMemPut:
823 * Write a string of bytes into NINDY's address space (960 memory).
824 ******************************************************************************/
825 int
826 ninMemPut( ninaddr, hostaddr, len )
827 long ninaddr; /* Destination address, in NINDY memory space */
828 unsigned char *hostaddr; /* Source address, in our memory space */
829 int len; /* Number of bytes to write */
830 {
831 unsigned char buf[BUFSIZE+20];
832 int cnt; /* Number of bytes in next transfer */
833 int origlen = len;
834
835 if ( old_nindy ){
836 OninMemPut( ninaddr, hostaddr, len );
837 return;
838 }
839 for ( ; len > 0; len -= BUFSIZE ){
840 cnt = len > BUFSIZE ? BUFSIZE : len;
841
842 buf[0] = 'M';
843 store_unsigned_integer (&buf[1], 4, ninaddr);
844 memcpy(buf + 5, hostaddr, cnt);
845 send( buf, cnt+5, NULL );
846
847 ninaddr += cnt;
848 hostaddr += cnt;
849 }
850 return origlen;
851 }
852
853 /******************************************************************************
854 * ninRegGet:
855 * Retrieve the contents of a 960 register, and return them as a long
856 * in host byte order.
857 *
858 * THIS ROUTINE CAN ONLY BE USED TO READ THE LOCAL, GLOBAL, AND
859 * ip/ac/pc/tc REGISTERS.
860 *
861 ******************************************************************************/
862 long
863 ninRegGet( regname )
864 char *regname; /* Register name recognized by NINDY, subject to the
865 * above limitations.
866 */
867 {
868 unsigned char outbuf[10];
869 unsigned char inbuf[20];
870
871 if ( old_nindy ){
872 return OninRegGet( regname );
873 }
874
875 sprintf( outbuf, "u%s:", regname );
876 send( outbuf, strlen(outbuf), inbuf );
877 return extract_unsigned_integer (inbuf, 4);
878 }
879
880 /******************************************************************************
881 * ninRegPut:
882 * Set the contents of a 960 register.
883 *
884 * THIS ROUTINE CAN ONLY BE USED TO SET THE LOCAL, GLOBAL, AND
885 * ip/ac/pc/tc REGISTERS.
886 *
887 ******************************************************************************/
888 ninRegPut( regname, val )
889 char *regname; /* Register name recognized by NINDY, subject to the
890 * above limitations.
891 */
892 long val; /* New contents of register, in host byte-order */
893 {
894 unsigned char buf[20];
895 int len;
896
897 if ( old_nindy ){
898 OninRegPut( regname, val );
899 return;
900 }
901
902 sprintf( buf, "U%s:", regname );
903 len = strlen(buf);
904 store_unsigned_integer (&buf[len], 4, val);
905 send( buf, len+4, NULL );
906 }
907
908 /******************************************************************************
909 * ninRegsGet:
910 * Get a dump of the contents of the entire 960 register set. The
911 * individual registers appear in the dump in the following order:
912 *
913 * pfp sp rip r3 r4 r5 r6 r7
914 * r8 r9 r10 r11 r12 r13 r14 r15
915 * g0 g1 g2 g3 g4 g5 g6 g7
916 * g8 g9 g10 g11 g12 g13 g14 fp
917 * pc ac ip tc fp0 fp1 fp2 fp3
918 *
919 * Each individual register comprises exactly 4 bytes, except for
920 * fp0-fp3, which are 8 bytes. All register values are in 960
921 * (little-endian) byte order.
922 *
923 ******************************************************************************/
924 ninRegsGet( regp )
925 unsigned char *regp; /* Where to place the register dump */
926 {
927 if ( old_nindy ){
928 OninRegsGet( regp );
929 return;
930 }
931 send( (unsigned char *) "r", 1, regp );
932 }
933
934
935 /******************************************************************************
936 * ninRegsPut:
937 * Initialize the entire 960 register set to a specified set of values.
938 * The format of the register value data should be the same as that
939 * returned by ninRegsGet.
940 *
941 * WARNING:
942 * All register values must be in 960 (little-endian) byte order.
943 *
944 ******************************************************************************/
945 ninRegsPut( regp )
946 char *regp; /* Pointer to desired values of registers */
947 {
948 /* Number of bytes that we send to nindy. I believe this is defined by
949 the protocol (it does not agree with REGISTER_BYTES). */
950 #define NINDY_REGISTER_BYTES ((36*4) + (4*8))
951 unsigned char buf[NINDY_REGISTER_BYTES+10];
952
953 if ( old_nindy ){
954 OninRegsPut( regp );
955 return;
956 }
957
958 buf[0] = 'R';
959 memcpy(buf+1, regp, NINDY_REGISTER_BYTES );
960 send( buf, NINDY_REGISTER_BYTES+1, NULL );
961 }
962
963
964 /******************************************************************************
965 * ninReset:
966 * Ask NINDY to perform a soft reset; wait for the reset to complete.
967 *
968 ******************************************************************************/
969 ninReset()
970 {
971 unsigned char ack;
972
973 if ( old_nindy ){
974 OninReset();
975 return;
976 }
977
978 while (1){
979 putpkt((unsigned char *) "X", 1 );
980 while (1){
981 if ( !rdnin(&ack,1,5) ){
982 /* Timed out */
983 break; /* Resend */
984 }
985 if ( ack == '+' ){
986 return;
987 }
988 }
989 }
990 }
991
992
993 /******************************************************************************
994 * ninSrq:
995 * Assume NINDY has stopped execution of the 960 application program in
996 * order to process a host service request (srq). Ask NINDY for the
997 * srq arguments, perform the requested service, and send an "srq
998 * complete" message so NINDY will return control to the application.
999 *
1000 ******************************************************************************/
1001 ninSrq()
1002 {
1003 /* FIXME: Imposes arbitrary limits on lengths of pathnames and such. */
1004 unsigned char buf[BUFSIZE];
1005 int retcode;
1006 unsigned char srqnum;
1007 int i;
1008 int offset;
1009 int arg[MAX_SRQ_ARGS];
1010
1011 if ( old_nindy ){
1012 OninSrq();
1013 return;
1014 }
1015
1016
1017 /* Get srq number and arguments
1018 */
1019 send((unsigned char *) "!", 1, buf );
1020
1021 srqnum = buf[0];
1022 for ( i=0, offset=1; i < MAX_SRQ_ARGS; i++, offset+=4 ){
1023 arg[i] = extract_unsigned_integer (&buf[offset], 4);
1024 }
1025
1026 /* Process Srq
1027 */
1028 switch( srqnum ){
1029 case BS_CLOSE:
1030 /* args: file descriptor */
1031 if ( arg[0] > 2 ){
1032 retcode = close( arg[0] );
1033 } else {
1034 retcode = 0;
1035 }
1036 break;
1037 case BS_CREAT:
1038 /* args: filename, mode */
1039 ninStrGet( arg[0], buf );
1040 retcode = creat(buf,arg[1]);
1041 break;
1042 case BS_OPEN:
1043 /* args: filename, flags, mode */
1044 ninStrGet( arg[0], buf );
1045 retcode = open(buf,arg[1],arg[2]);
1046 break;
1047 case BS_READ:
1048 /* args: file descriptor, buffer, count */
1049 retcode = read(arg[0],buf,arg[2]);
1050 if ( retcode > 0 ){
1051 ninMemPut( arg[1], buf, retcode );
1052 }
1053 break;
1054 case BS_SEEK:
1055 /* args: file descriptor, offset, whence */
1056 retcode = lseek(arg[0],arg[1],arg[2]);
1057 break;
1058 case BS_WRITE:
1059 /* args: file descriptor, buffer, count */
1060 ninMemGet( arg[1], buf, arg[2] );
1061 retcode = write(arg[0],buf,arg[2]);
1062 break;
1063 default:
1064 retcode = -1;
1065 break;
1066 }
1067
1068 /* Send request termination status to NINDY
1069 */
1070 buf[0] = 'e';
1071 store_unsigned_integer (&buf[1], 4, retcode);
1072 send( buf, 5, NULL );
1073 }
1074
1075
1076 /******************************************************************************
1077 * ninStopWhy:
1078 * Assume the application program has stopped (i.e., a DLE was received
1079 * from NINDY). Ask NINDY for status information describing the
1080 * reason for the halt.
1081 *
1082 * Returns a non-zero value if the user program has exited, 0 otherwise.
1083 * Also returns the following information, through passed pointers:
1084 * - why: an exit code if program the exited; otherwise the reason
1085 * why the program halted (see stop.h for values).
1086 * - contents of register ip (little-endian byte order)
1087 * - contents of register sp (little-endian byte order)
1088 * - contents of register fp (little-endian byte order)
1089 ******************************************************************************/
1090 char
1091 ninStopWhy( whyp, ipp, fpp, spp )
1092 unsigned char *whyp; /* Return the 'why' code through this pointer */
1093 long *ipp; /* Return contents of register ip through this pointer */
1094 long *fpp; /* Return contents of register fp through this pointer */
1095 long *spp; /* Return contents of register sp through this pointer */
1096 {
1097 unsigned char buf[30];
1098 extern char OninStopWhy ();
1099
1100 if ( old_nindy ){
1101 return OninStopWhy( whyp, ipp, fpp, spp );
1102 }
1103 send((unsigned char *) "?", 1, buf );
1104
1105 *whyp = buf[1];
1106 memcpy ((char *)ipp, &buf[2], sizeof (*ipp));
1107 memcpy ((char *)fpp, &buf[6], sizeof (*ipp));
1108 memcpy ((char *)spp, &buf[10], sizeof (*ipp));
1109 return buf[0];
1110 }
1111
1112 /******************************************************************************
1113 * ninStrGet:
1114 * Read a '\0'-terminated string of data out of the 960 memory space.
1115 *
1116 ******************************************************************************/
1117 static
1118 ninStrGet( ninaddr, hostaddr )
1119 unsigned long ninaddr; /* Address of string in NINDY memory space */
1120 unsigned char *hostaddr; /* Address of the buffer to which string should
1121 * be copied.
1122 */
1123 {
1124 unsigned char cmd[5];
1125
1126 cmd[0] = '"';
1127 store_unsigned_integer (&cmd[1], 4, ninaddr);
1128 send( cmd, 5, hostaddr );
1129 }
1130
1131 #if 0
1132 /* Not used. */
1133
1134 /******************************************************************************
1135 * ninVersion:
1136 * Ask NINDY for version information about itself.
1137 * The information is sent as an ascii string in the form "x.xx,<arch>",
1138 * where,
1139 * x.xx is the version number
1140 * <arch> is the processor architecture: "KA", "KB", "MC", "CA" *
1141 *
1142 ******************************************************************************/
1143 int
1144 ninVersion( p )
1145 unsigned char *p; /* Where to place version string */
1146 {
1147
1148 if ( old_nindy ){
1149 return OninVersion( p );
1150 }
1151 send((unsigned char *) "v", 1, p );
1152 return strlen(p);
1153 }
1154 #endif /* 0 */