OSDN Git Service

Initial revision
[pf3gnuchains/pf3gnuchains3x.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 */