home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / gdb-4.9 / gdb / nindy-share / nindy.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-12  |  39.3 KB  |  1,470 lines

  1. /*****************************************************************************
  2.  * Copyright 1990, 1992 Free Software Foundation, Inc.
  3.  *
  4.  * This code was donated by Intel Corp.
  5.  *
  6.  * Intel hereby grants you permission to copy, modify, and 
  7.  * distribute this software and its documentation.  Intel grants
  8.  * this permission provided that the above copyright notice 
  9.  * appears in all copies and that both the copyright notice and
  10.  * this permission notice appear in supporting documentation.  In
  11.  * addition, Intel grants this permission provided that you
  12.  * prominently mark as not part of the original any modifications
  13.  * made to this software or documentation, and that the name of 
  14.  * Intel Corporation not be used in advertising or publicity 
  15.  * pertaining to distribution of the software or the documentation 
  16.  * without specific, written prior permission.  
  17.  *
  18.  * Intel Corporation does not warrant, guarantee or make any 
  19.  * representations regarding the use of, or the results of the use
  20.  * of, the software and documentation in terms of correctness, 
  21.  * accuracy, reliability, currentness, or otherwise; and you rely
  22.  * on the software, documentation and results solely at your own risk.
  23.  *****************************************************************************/
  24.  
  25. static char rcsid[] =
  26.     "Id: nindy.c,v 1.1.1.1 1991/03/28 16:20:57 rich Exp $";
  27.  
  28. /******************************************************************************
  29.  *
  30.  *             NINDY INTERFACE ROUTINES
  31.  *
  32.  * The routines in this file define and implement an interface between code
  33.  * (such as a high-level debugger) running on a remote host and the NINDY
  34.  * ROM monitor on an i960 board.  These routines are to be linked with 
  35.  * and called by the host code.
  36.  *
  37.  * These routines handle both the formatting/transferring of commands to NINDY
  38.  * and the receipt/formatting of data returned in response to them.  The
  39.  * actual transfer protocol is hidden from the host programmer within them.
  40.  * For a full description of the lowest level NINDY/host transfer protocol,
  41.  * see the block header of the file gdb.c, in the NINDY source code.
  42.  *
  43.  * The caller of these routines should be aware that:
  44.  *
  45.  * (1) ninConnect() should be called to open communications with the
  46.  *     remote NINDY board before any of the other routines are invoked.
  47.  *
  48.  * (2) almost all interactions are driven by the host: nindy sends information
  49.  *     in response to host commands.
  50.  *
  51.  * (3) the lone exception to (2) is the single character DLE (^P, 0x10).
  52.  *     Receipt of a DLE from NINDY indicates that the application program
  53.  *     running under NINDY has stopped execution and that NINDY is now
  54.  *     available to talk to the host (all other communication received after
  55.  *     the application has been started should be presumed to come from the
  56.  *     application and should be passed on by the host to stdout).
  57.  *
  58.  * (4) the reason the application program stopped can be determined with the
  59.  *     ninStopWhy() function.  There are three classes of stop reasons:
  60.  *
  61.  *    (a) the application has terminated execution.
  62.  *        The host should take appropriate action.
  63.  *
  64.  *    (b) the application had a fault or trace event.
  65.  *        The host should take appropriate action.
  66.  *
  67.  *    (c) the application wishes to make a service request (srq) of the host;
  68.  *        e.g., to open/close a file, read/write a file, etc.  The ninSrq()
  69.  *        function should be called to determine the nature of the request
  70.  *        and process it.
  71.  *
  72.  * WARNING: Changes made here should be tested in both gdb960 and comm960.
  73.  *
  74.  ******************************************************************************/
  75.  
  76. #include <stdio.h>
  77. #include <sys/ioctl.h>
  78. #include <sys/types.h>    /* Needed by file.h on Sys V */
  79. #include <sys/file.h>
  80. #include <signal.h>
  81. #include <sys/stat.h>
  82. #include <fcntl.h>    /* Needed on Sys V */
  83. #include "defs.h" /* for xmalloc */
  84. #include "ttycntl.h"
  85. #include "block_io.h"
  86. #include "wait.h"
  87. #include "env.h"
  88.  
  89.  
  90. #ifdef USG
  91. #    include <unistd.h>
  92. #    include "sysv.h"
  93. #else    /* BSD */
  94. #    include "string.h"
  95. #    include <sys/time.h>
  96. #endif
  97.  
  98. #ifndef ERROR
  99. #define ERROR    -1
  100. #endif
  101.  
  102. #define DLE    0x10    /* ^P */
  103. #define XON    0x11    /* ^Q */
  104. #define XOFF    0x13    /* ^S */
  105. #define ESC    0x1b
  106.  
  107.  
  108. #define NINDY_REGISTER_BYTES    ((36*4) + (4*8))
  109.  
  110. #define TIMEOUT        -1
  111.  
  112. extern void free();
  113.  
  114. static int quiet = 0;    /* 1 => stifle unnecessary messages */
  115. static int nindy_fd;    /* File descriptor of tty connected to 960/NINDY board*/
  116.  
  117. static int old_nindy = 0; /* 1 => use old (hex) communication protocol */
  118. static ninStrGet();
  119.  
  120.         /****************************
  121.          *                          *
  122.          *  MISCELLANEOUS UTILTIES  *
  123.          *                          *
  124.          ****************************/
  125.  
  126.  
  127. #if 0
  128. /******************************************************************************
  129.  * byteswap:
  130.  *    If the host byte order is different from 960 byte order (i.e., the
  131.  *    host is big-endian), reverse the bytes in the passed value;  otherwise,
  132.  *    return the passed value unchanged.
  133.  *
  134.  ******************************************************************************/
  135. static
  136. long
  137. byteswap( n )
  138.     long n;
  139. {
  140.     long rev;
  141.     int i;
  142.     static short test = 0x1234;
  143.  
  144.     if (*((char *) &test) == 0x12) {
  145.         /*
  146.          * Big-endian host, swap the bytes.
  147.          */
  148.         rev = 0;
  149.         for ( i = 0; i < sizeof(n); i++ ){
  150.             rev <<= 8;
  151.             rev |= n & 0xff;
  152.             n >>= 8;
  153.         }
  154.         n = rev;
  155.     }
  156.     return n;
  157. }
  158. #endif /* 0 */
  159.  
  160.  
  161. /******************************************************************************
  162.  * get_int:
  163.  *    Copy the little-endian integer pointed at by 'p'  and return it in
  164.  *    the host byte order.  'p' may be an unaligned address, so do the copy
  165.  *    a byte at a time.
  166.  ******************************************************************************/
  167. int
  168. get_int( p )
  169.     unsigned char *p;
  170. {
  171.     int n;
  172.     int i;
  173.  
  174.     n = 0;
  175.     p += sizeof(int) - 1;
  176.     for ( i = 0; i < sizeof(n); i++ ){
  177.         n <<= 8;
  178.         n |= *p--;
  179.     }
  180.  
  181.     return n;
  182. }
  183.  
  184.  
  185. /******************************************************************************
  186.  * put_int:
  187.  *    Copy the integer 'n' (which is in host byte order) to the location
  188.  *    pointed at by 'p', leaving it in little-endian byte order.
  189.  *    'p' may be an unaligned address, so do the move a byte at a time.
  190.  ******************************************************************************/
  191. int
  192. put_int( p, n )
  193.     unsigned char *p;
  194.     int n;
  195. {
  196.     int i;
  197.  
  198.     for ( i = 0; i < sizeof(n); i++ ){
  199.         *p++ = n;
  200.         n >>= 8;
  201.     }
  202. }
  203.  
  204.  
  205. /******************************************************************************
  206.  * say:
  207.  *    This is a printf that takes at most two arguments (in addition to the
  208.  *    format string) and that outputs nothing if verbose output has been
  209.  *    suppressed.
  210.  ******************************************************************************/
  211. /* FIXME: use varargs for this.  */
  212. static
  213. say( fmt, arg1, arg2 )
  214.     char *fmt;
  215.     int arg1, arg2;
  216. {
  217.     if ( !quiet ){
  218.         printf( fmt, arg1, arg2 );
  219.         fflush( stdout );
  220.     }
  221. }
  222.  
  223. /******************************************************************************
  224.  * exists:
  225.  *    Creates a full pathname by concatenating up to three name components
  226.  *    onto a specified base name; optionally looks up the base name as a
  227.  *    runtime environment variable;  and checks to see if the file or
  228.  *    directory specified by the pathname actually exists.
  229.  *
  230.  *    Returns:  the full pathname if it exists, NULL otherwise.
  231.  *        (returned pathname is in malloc'd memory and must be freed
  232.  *        by caller).
  233.  *****************************************************************************/
  234. static
  235. char *
  236. exists( base, c1, c2, c3, env )
  237.     char *base;        /* Base directory of path */
  238.     char *c1, *c2, *c3;    /* Components (subdirectories and/or file name) to be
  239.              *    appended onto the base directory name.  One or
  240.              *    more may be omitted by passing NULL pointers.
  241.              */
  242.     int env;        /* If 1, '*base' is the name of an environment variable
  243.              *    to be examined for the base directory name;
  244.              *    otherwise, '*base' is the actual name of the
  245.              *    base directory.
  246.              */
  247. {
  248.     struct stat buf;/* For call to 'stat' -- never examined */
  249.     char *path;    /* Pointer to full pathname (malloc'd memory) */
  250.     int len;    /* Length of full pathname (incl. terminator) */
  251.     extern char *getenv();
  252.  
  253.  
  254.     if ( env ){
  255.         base = getenv( base );
  256.         if ( base == NULL ){
  257.             return NULL;
  258.         }
  259.     }
  260.  
  261.     len = strlen(base) + 4;
  262.             /* +4 for terminator and "/" before each component */
  263.     if ( c1 != NULL ){
  264.         len += strlen(c1);
  265.     }
  266.     if ( c2 != NULL ){
  267.         len += strlen(c2);
  268.     }
  269.     if ( c3 != NULL ){
  270.         len += strlen(c3);
  271.     }
  272.  
  273.     path = xmalloc( len );
  274.  
  275.     strcpy( path, base );
  276.     if ( c1 != NULL ){
  277.         strcat( path, "/" );
  278.         strcat( path, c1 );
  279.         if ( c2 != NULL ){
  280.             strcat( path, "/" );
  281.             strcat( path, c2 );
  282.             if ( c3 != NULL ){
  283.                 strcat( path, "/" );
  284.                 strcat( path, c3 );
  285.             }
  286.         }
  287.     }
  288.  
  289.     if ( stat(path,&buf) != 0 ){
  290.         free( path );
  291.         path = NULL;
  292.     }
  293.     return path;
  294. }
  295.  
  296.         /*****************************
  297.          *                           *
  298.          *  LOW-LEVEL COMMUNICATION  *
  299.          *                           *
  300.          *****************************/
  301.  
  302. /******************************************************************************
  303.  * timed_read:
  304.  *    Read up to 'n' characters (less if fewer are available) from the NINDY
  305.  *    tty. Wait up to 'timeout' seconds for something to arrive.  Return
  306.  *    the number of characters read, 0 on timeout.
  307.  ******************************************************************************/
  308. #ifdef USG
  309.  
  310. static int saw_alarm;
  311.  
  312. static void
  313. alarm_handler()
  314. {
  315.     saw_alarm = 1;
  316. }
  317.  
  318. static
  319. int
  320. timed_read(buf,n,timeout)
  321.     unsigned char * buf;    /* Where to put the read characters    */
  322.     int n;            /* Max number of characters to read    */
  323.     int timeout;        /* Timeout, in seconds            */
  324. {
  325.         void (*old_alarm)();    /* Save alarm signal handler here on entry */
  326.     int cnt;
  327.  
  328.  
  329.         old_alarm = signal( SIGALRM,alarm_handler );
  330.         saw_alarm = 0;
  331.         alarm(timeout);
  332.         do {
  333.         cnt = n;
  334.                 TTY_NBREAD(nindy_fd,cnt,buf);
  335.         } while ( (cnt <= 0) && !saw_alarm );
  336.  
  337.         alarm(0);
  338.         signal( SIGALRM,old_alarm );
  339.  
  340.     return saw_alarm ? 0 : cnt;
  341. }
  342.  
  343. #else        /* BSD */
  344.  
  345. static
  346. int
  347. timed_read(buf,n,timeout)
  348.     unsigned char * buf;    /* Where to put the read characters    */
  349.     int n;            /* Max number of characters to read    */
  350.     int timeout;        /* Timeout, in seconds            */
  351. {
  352.     struct timeval t;
  353.     fd_set f;
  354.  
  355.     t.tv_sec = (long) timeout;
  356.     t.tv_usec= 0;
  357.  
  358.     FD_ZERO( &f );
  359.     FD_SET( nindy_fd, &f );
  360.     if ( select(nindy_fd+1,&f,0,0,&t) ){
  361.         return read( nindy_fd, buf, n );
  362.     } else {
  363.         return 0;
  364.     }
  365. }
  366. #endif /* USG */
  367.  
  368. /******************************************************************************
  369.  * rdnin:
  370.  *    Read *exactly* 'n' characters from the NINDY tty.  Translate escape
  371.  *    sequences into single characters, counting each such sequence as 
  372.  *    1 character.
  373.  *
  374.  *    An escape sequence consists of ESC and a following character.  The
  375.  *    ESC is discarded and the other character gets bit 0x40 cleared --
  376.  *    thus ESC P == ^P, ESC S == ^S, ESC [ == ESC, etc.
  377.  *
  378.  *    Return 1 if successful, 0 if more than 'timeout' seconds pass without
  379.  *    any input.
  380.  ******************************************************************************/
  381. static
  382. int
  383. rdnin(buf,n,timeout)
  384.     unsigned char * buf;    /* Where to place characters read    */
  385.     int n;            /* Number of characters to read        */
  386.     int timeout;        /* Timeout, in seconds            */
  387. {
  388.     static unsigned char *mybuf = NULL;
  389.                 /* Dynamically allocated local buffer */
  390.     static int mybuflen = 0;
  391.                 /* Current size of local buffer    */
  392.     int escape_seen;    /* 1 => last character of a read was an ESC */
  393.     int nread;        /* Number of chars returned by timed_read() */
  394.     unsigned char c;
  395.     int i;
  396.  
  397.     /* Make sure local buffer is big enough
  398.      */
  399.     if ( n > mybuflen ){
  400.         if ( mybuf ){
  401.             free( mybuf );
  402.         }
  403.         mybuf = (unsigned char *) xmalloc( mybuflen=n );
  404.     }
  405.  
  406.  
  407.     /* More than one loop will be necessary if there are any
  408.      * escape sequences in the input
  409.      */
  410.     escape_seen = 0;
  411.     while ( n ){
  412.         nread = timed_read(mybuf,n,timeout);
  413.         if ( nread <= 0 ){
  414.             return 0;    /* TIMED OUT */
  415.         }
  416.  
  417.         /* Copy characters from local buffer to caller's buffer,
  418.          * converting escape sequences as they're encountered.
  419.          */
  420.         for ( i = 0; i < nread; i++ ){
  421.             c = mybuf[i];
  422.             if ( escape_seen ){
  423.                 escape_seen = 0;
  424.                 c &= ~0x40;
  425.             } else if ( c == ESC ){
  426.                 if ( ++i >= nread ){
  427.                     /* Need to refill local buffer */
  428.                     escape_seen = 1;
  429.                     break;
  430.                 }
  431.                 c = mybuf[i] & ~0x40;
  432.             }
  433.             *buf++ = c;
  434.             n--;
  435.         }
  436.     }
  437.     return 1;
  438. }
  439.  
  440.  
  441. /******************************************************************************
  442.  * getpkt:
  443.  *    Read a packet from a remote NINDY, with error checking, into the
  444.  *    indicated buffer.
  445.  *
  446.  *    Return packet status byte on success, TIMEOUT on failure.
  447.  ******************************************************************************/
  448. static
  449. int
  450. getpkt(buf)
  451.      unsigned char *buf;
  452. {
  453.     int i;
  454.     unsigned char hdr[3];    /* Packet header:
  455.                  *    hdr[0] = low byte of message length
  456.                  *    hdr[1] = high byte of message length
  457.                  *    hdr[2] = message status
  458.                  */
  459.     int cnt;        /* Message length (status byte + data)    */
  460.     unsigned char cs_calc;    /* Checksum calculated            */
  461.     unsigned char cs_recv;    /* Checksum received            */
  462.     static char errfmt[] =
  463.             "Bad checksum (recv=0x%02x; calc=0x%02x); retrying\r\n";
  464.  
  465.     while (1){
  466.         if ( !rdnin(hdr,3,5) ){
  467.             return TIMEOUT;
  468.         }
  469.         cnt = (hdr[1]<<8) + hdr[0] - 1;
  470.                     /* -1 for status byte (already read) */
  471.  
  472.         /* Caller's buffer may only be big enough for message body,
  473.          * without status byte and checksum, so make sure to read
  474.          * checksum into a separate buffer.
  475.          */
  476.         if ( !rdnin(buf,cnt,5) || !rdnin(&cs_recv,1,5) ){
  477.             return TIMEOUT;
  478.         }
  479.  
  480.         /* Calculate checksum
  481.          */
  482.         cs_calc = hdr[0] + hdr[1] + hdr[2];
  483.         for ( i = 0; i < cnt; i++ ){
  484.             cs_calc += buf[i];
  485.         }
  486.         if ( cs_calc == cs_recv ){
  487.             write (nindy_fd, "+", 1);
  488.             return hdr[2];
  489.         }
  490.     
  491.         /* Bad checksum: report, send NAK, and re-receive
  492.          */
  493.         fprintf(stderr, errfmt, cs_recv, cs_calc );
  494.         write (nindy_fd, "-", 1);
  495.     }
  496. }
  497.  
  498.  
  499. /******************************************************************************
  500.  * putpkt:
  501.  *    Send a packet to NINDY, checksumming it and converting special
  502.  *    characters to escape sequences.
  503.  ******************************************************************************/
  504.  
  505. /* This macro puts the character 'c' into the buffer pointed at by 'p',
  506.  * and increments the pointer.  If 'c' is one of the 4 special characters
  507.  * in the transmission protocol, it is converted into a 2-character
  508.  * escape sequence.
  509.  */
  510. #define PUTBUF(c,p)                        \
  511.     if ( c == DLE || c == ESC || c == XON || c == XOFF ){    \
  512.         *p++ = ESC;                    \
  513.         *p++ = c | 0x40;                \
  514.     } else {                        \
  515.         *p++ = c;                    \
  516.     }
  517.  
  518. static
  519. putpkt( msg, len )
  520.     unsigned char *msg;    /* Command to be sent, without lead ^P (\020) or checksum */
  521.     int len;    /* Number of bytes in message            */
  522. {
  523.     static char *buf = NULL;/* Local buffer -- build packet here    */
  524.     static int maxbuf = 0;    /* Current length of buffer        */
  525.     unsigned char ack;    /* Response received from NINDY        */
  526.     unsigned char checksum;    /* Packet checksum            */
  527.     char *p;        /* Pointer into buffer            */
  528.     int lenhi, lenlo;     /* High and low bytes of message length    */
  529.     int i;
  530.  
  531.  
  532.     /* Make sure local buffer is big enough.  Must include space for
  533.      * packet length, message body, and checksum.  And in the worst
  534.      * case, each character would expand into a 2-character escape
  535.      * sequence.
  536.      */
  537.     if ( maxbuf < ((2*len)+10) ){
  538.         if ( buf ){
  539.             free( buf );
  540.         }
  541.         buf = xmalloc( maxbuf=((2*len)+10) );
  542.     }
  543.  
  544.     /* Attention, NINDY!
  545.      */
  546.     write( nindy_fd, "\020", 1 );
  547.  
  548.  
  549.     lenlo = len & 0xff;
  550.     lenhi = (len>>8) & 0xff;
  551.     checksum = lenlo + lenhi;
  552.     p = buf;
  553.  
  554.     PUTBUF( lenlo, p );
  555.     PUTBUF( lenhi, p );
  556.  
  557.     for ( i=0; i<len; i++ ){
  558.         PUTBUF( msg[i], p );
  559.         checksum += msg[i];
  560.     }
  561.  
  562.     PUTBUF( checksum, p );
  563.  
  564.     /* Send checksummed message over and over until we get a positive ack
  565.      */
  566.     write( nindy_fd, buf, p-buf );
  567.     while (1){
  568.         if ( !rdnin(&ack,1,5) ){
  569.             /* timed out */
  570.             fprintf(stderr,"ACK timed out; resending\r\n");
  571.             write(nindy_fd,"\020",1);/* Attention, NINDY! */
  572.             write( nindy_fd, buf, p-buf );
  573.         } else if ( ack == '+' ){
  574.             return;
  575.         } else if ( ack == '-' ){
  576.             fprintf( stderr, "Remote NAK; resending\r\n" );
  577.             write( nindy_fd, buf, p-buf );
  578.         } else {
  579.             fprintf( stderr, "Bad ACK, ignored: <%c>\r\n", ack );
  580.         }
  581.     }
  582. }
  583.  
  584.  
  585.  
  586. /******************************************************************************
  587.  * send:
  588.  *    Send a message to a remote NINDY.  Check message status byte
  589.  *    for error responses.  If no error, return NINDY reponse (if any).
  590.  ******************************************************************************/
  591. static
  592. send( out, len, in )
  593.     unsigned char *out;    /* Message to be sent to NINDY            */
  594.     int len;        /* Number of meaningful bytes in out buffer    */
  595.     unsigned char *in;    /* Where to put response received from NINDY    */
  596. {
  597.     char *fmt;
  598.     int status;
  599.     static char *errmsg[] = {
  600.         "",                        /* 0 */
  601.         "Buffer overflow",                /* 1 */
  602.         "Unknown command",                /* 2 */
  603.         "Wrong amount of data to load register(s)",    /* 3 */
  604.         "Missing command argument(s)",            /* 4 */
  605.         "Odd number of digits sent to load memory",    /* 5 */
  606.         "Unknown register name",            /* 6 */
  607.         "No such memory segment",            /* 7 */
  608.         "No breakpoint available",            /* 8 */
  609.         "Can't set requested baud rate",        /* 9 */
  610.     };
  611. #    define NUMERRS    ( sizeof(errmsg) / sizeof(errmsg[0]) )
  612.  
  613.     static char err1[] = "Unknown error response from NINDY: #%d\r\n";
  614.     static char err2[] = "Error response #%d from NINDY: %s\r\n";
  615.  
  616.     while (1){
  617.         putpkt(out,len);
  618.         status = getpkt(in);
  619.         if ( status == TIMEOUT ){
  620.             fprintf( stderr, "Response timed out; resending\r\n" );
  621.         } else {
  622.             break;
  623.         }
  624.     }
  625.  
  626.     if ( status ){
  627.         fmt =  status > NUMERRS ? err1 : err2;
  628.         fprintf( stderr, fmt, status, errmsg[status] );
  629.         abort();
  630.     }
  631. }
  632.  
  633.         /************************
  634.          *                      *
  635.          *  BAUD RATE ROUTINES  *
  636.          *                      *
  637.          ************************/
  638.  
  639. /* Table of baudrates known to be acceptable to NINDY.  Each baud rate
  640.  * appears both as character string and as a Unix baud rate constant.
  641.  */
  642. struct baudrate {
  643.     char *string;
  644.     int rate;
  645. };
  646.  
  647. static struct baudrate baudtab[] = {
  648.      "1200", B1200,
  649.      "2400", B2400,
  650.      "4800", B4800,
  651.      "9600", B9600,
  652.     "19200", B19200,
  653.     "38400", B38400,
  654.     NULL,    0        /* End of table */
  655. };
  656.  
  657.  
  658. /******************************************************************************
  659.  * parse_baudrate:
  660.  *    Look up the passed baud rate in the baudrate table.  If found, change
  661.  *    our internal record of the current baud rate, but don't do anything
  662.  *    about the tty just now.
  663.  *
  664.  *    Return pointer to baudrate structure on success, NULL on failure.
  665.  ******************************************************************************/
  666. static
  667. struct baudrate *
  668. parse_baudrate(s)
  669.     char *s;    /* Desired baud rate, as an ASCII (decimal) string */
  670. {
  671.     int i;
  672.  
  673.     for ( i=0; baudtab[i].string != NULL; i++ ){
  674.         if ( !strcmp(baudtab[i].string,s) ){
  675.             return &baudtab[i];
  676.         }
  677.     }
  678.     return NULL;
  679. }
  680.  
  681. /******************************************************************************
  682.  * try_baudrate:
  683.  *    Try speaking to NINDY via the specified file descriptor at the
  684.  *    specified baudrate.  Assume success if we can send an empty command
  685.  *    with a bogus checksum and receive a NAK (response of '-') back within
  686.  *    one second.
  687.  *
  688.  *    Return 1 on success, 0 on failure.
  689.  ******************************************************************************/
  690.  
  691. static int
  692. try_baudrate( fd, brp )
  693.     int fd;
  694.     struct baudrate *brp;
  695. {
  696.     TTY_STRUCT tty;
  697.     unsigned char c;
  698.     
  699.  
  700.     /* Set specified baud rate and flush all pending input */
  701.     ioctl( fd, TIOCGETP, &tty );
  702.     TTY_REMOTE( tty, brp->rate );
  703.     ioctl( fd, TIOCSETP, &tty );
  704.     tty_flush( fd );
  705.  
  706.     /* Send empty command with bad checksum, hope for NAK ('-') response */
  707.     write( fd, "\020\0\0\001", 4 );
  708.     if ( !rdnin(&c,1,1) ){
  709.         /* timed out */
  710.         return 0;
  711.     } else {
  712.         return (c == '-');
  713.     }
  714. }
  715.  
  716. /******************************************************************************
  717.  * autobaud:
  718.  *    Get NINDY talking over the specified file descriptor at the specified
  719.  *    baud rate.  First see if NINDY's already talking at 'baudrate'.  If
  720.  *    not, run through all the legal baudrates in 'baudtab' until one works,
  721.  *    and then tell NINDY to talk at 'baudrate' instead.
  722.  ******************************************************************************/
  723. static
  724. autobaud( fd, brp )
  725.     int fd;
  726.     struct baudrate *brp;
  727. {
  728.     int i;
  729.     TTY_STRUCT tty;
  730.     int failures;
  731.  
  732.  
  733.     say("NINDY at wrong baud rate? Trying to autobaud...\n");
  734.     failures = i = 0;
  735.     while ( 1 ){
  736.         say( "\r%s...   ", baudtab[i].string );
  737.         if ( try_baudrate(fd, &baudtab[i]) ){
  738.             break;
  739.         }
  740.         if ( baudtab[++i].string == NULL ){
  741.             /* End of table -- wraparound */
  742.             i = 0;
  743.             if ( failures++ ){
  744.                 say("\nAutobaud failed again.  Giving up.\n");
  745.                 exit(1);
  746.             } else {
  747.                 say("\nAutobaud failed. Trying again...\n");
  748.             }
  749.         }
  750.     }
  751.  
  752.     /* Found NINDY's current baud rate;  now change it.
  753.      */
  754.     say("Changing NINDY baudrate to %s\n", brp->string);
  755.     ninBaud( brp->string );
  756.  
  757.     /* Change our baud rate back to rate to which we just set NINDY.
  758.      */
  759.     ioctl( fd, TIOCGETP, &tty );
  760.     TTY_REMOTE( tty, brp->rate );
  761.     ioctl( fd, TIOCSETP, &tty );
  762. }
  763.  
  764. /*****************************************************************************
  765.  * coffstrip:
  766.  *    Passed the name of an executable object file in either b.out or
  767.  *    COFF format.
  768.  *
  769.  *    If the file is in b.out format, it is converted to little-endian
  770.  *    COFF format (i.e., the format suitable for downloading to NINDY).
  771.  *    In either case, the COFF file is then stripped of all relocation
  772.  *    and symbol information, to speed up its download.
  773.  *
  774.  * RETURNS:
  775.  *    pointer to the name of the stripped COFF file (a tmp file that has
  776.  *    been created and closed); NULL on error.
  777.  *****************************************************************************/
  778.  
  779. #if 0
  780. #define STRIP    "bfd_strip"    /* Name of bfd strip utility    */
  781. #endif
  782. #define NINDY_OBJ    "coff-Intel-little"
  783.  
  784. char *
  785. coffstrip( fn )
  786.     char *fn;    /* Name of object file */
  787. {
  788.     extern char *mktemp();
  789.     static char template[] = "/tmp/commXXXXXX";
  790.     static char newfile[sizeof template];
  791.     char *strip;    /* Pointer to full pathname of strip utility    */
  792.     int success;    /* Return value                    */
  793.     int pid;    /* Process ID of xmodem transfer utility    */
  794.     WAITTYPE w;    /* xmodem transfer completion status        */
  795.     int wret;    /* Value returned by wait            */
  796.     char *tempfile;    /* Stripped copy of object file            */
  797.     char buf[400];
  798.  
  799.  
  800.     strcpy (newfile, template);
  801.     tempfile = mktemp( newfile );
  802.  
  803. #if 0
  804.     /* Make sure the strip utility is findable.
  805.      */
  806.     if ( ((strip = exists("G960BIN",STRIP,NULL,NULL,1)) == NULL)
  807.     &&   ((strip = exists("G960BASE","bin",STRIP, NULL,1)) == NULL)
  808. #ifdef HOST
  809.     &&   ((strip = exists(DEFAULT_BASE,HOST,"bin",STRIP,0)) == NULL)
  810. #endif
  811.     ){
  812.         fprintf(stderr,"Can't find '%s' utility\n",STRIP);
  813.         fprintf(stderr,"Check env variables G960BIN and G960BASE\n");
  814.         return NULL;
  815.     }
  816. #endif /* 0 */
  817.  
  818.     success = 0;
  819.     sprintf( buf, "cp %s %s", fn, tempfile );
  820.     printf ("%s\n", buf);
  821.     if ( system(buf) == 0 ){
  822.         sprintf(buf, "%s -d %s %s", STRIP, NINDY_OBJ, tempfile);
  823.         printf ("%s\n", buf);
  824.         if ( system(buf) == 0 ){
  825.             return tempfile;
  826.         }
  827.     }
  828.  
  829.     return NULL;
  830. }
  831.  
  832.         /**********************************
  833.          *                  *
  834.          *   NINDY INTERFACE ROUTINES      *
  835.          *                                  *
  836.          * ninConnect *MUST* be the first *
  837.          * one of these routines called.  *
  838.          **********************************/
  839.  
  840.  
  841. /******************************************************************************
  842.  * ninBaud:
  843.  *    Ask NINDY to change the baud rate on its serial port.
  844.  *    Assumes we know the baud rate at which NINDY's currently talking.
  845.  ******************************************************************************/
  846. ninBaud( baudrate )
  847.     char *baudrate;    /* Desired baud rate, as a string of ASCII decimal
  848.              * digits.
  849.              */
  850. {
  851.     unsigned char msg[100];
  852.  
  853.     if ( old_nindy ){
  854.         OninBaud( baudrate );
  855.         return;
  856.     }
  857.  
  858.     tty_flush( nindy_fd );
  859.  
  860.     /* Can't use "send" because NINDY reply will be unreadable after
  861.      * baud rate change.
  862.      */
  863.     sprintf( msg, "z%s", baudrate );
  864.     putpkt( msg, strlen(msg)+1 );    /* "+1" to send terminator too */
  865. }
  866.  
  867.  
  868. /******************************************************************************
  869.  * ninBptDel:
  870.  *    Ask NINDY to delete the specified type of *hardware* breakpoint at
  871.  *    the specified address.  If the 'addr' is -1, all breakpoints of
  872.  *    the specified type are deleted.
  873.  ******************************************************************************/
  874. ninBptDel( addr, type )
  875.     long addr;    /* Address in 960 memory    */
  876.     char type;    /* 'd' => data bkpt, 'i' => instruction breakpoint */
  877. {
  878.     unsigned char buf[10];
  879.  
  880.     if ( old_nindy ){
  881.         OninBptDel( addr, type == 'd' ? 1 : 0 );
  882.         return;
  883.     }
  884.  
  885.     buf[0] = 'b';
  886.     buf[1] = type;
  887.  
  888.     if ( addr == -1 ){
  889.         send( buf, 2, NULL );
  890.     } else {
  891.         put_int( &buf[2], addr );
  892.         send( buf, 6, NULL );
  893.     }
  894. }
  895.  
  896.  
  897. /******************************************************************************
  898.  * ninBptSet:
  899.  *    Ask NINDY to set the specified type of *hardware* breakpoint at
  900.  *    the specified address.
  901.  ******************************************************************************/
  902. ninBptSet( addr, type )
  903.     long addr;    /* Address in 960 memory    */
  904.     char type;    /* 'd' => data bkpt, 'i' => instruction breakpoint */
  905. {
  906.     unsigned char buf[10];
  907.  
  908.     if ( old_nindy ){
  909.         OninBptSet( addr, type == 'd' ? 1 : 0 );
  910.         return;
  911.     }
  912.  
  913.  
  914.     buf[0] = 'B';
  915.     buf[1] = type;
  916.     put_int( &buf[2], addr );
  917.     send( buf, 6, NULL );
  918. }
  919.  
  920.  
  921. /******************************************************************************
  922.  * ninConnect:
  923.  *    Open the specified tty.  Get communications working at the specified
  924.  *    baud rate.  Flush any pending I/O on the tty.
  925.  *
  926.  *    Return the file descriptor, or -1 on failure.
  927.  ******************************************************************************/
  928. int
  929. ninConnect( name, baudrate, brk, silent, old_protocol )
  930.     char *name;        /* "/dev/ttyXX" to be opened            */
  931.     char *baudrate;/* baud rate: a string of ascii decimal digits (eg,"9600")*/
  932.     int brk;        /* 1 => send break to tty first thing after opening it*/
  933.     int silent;        /* 1 => stifle unnecessary messages when talking to 
  934.              *    this tty.
  935.              */
  936.     int old_protocol;
  937. {
  938.     int i;
  939.     char *p;
  940.     struct baudrate *brp;
  941.  
  942.     /* We will try each of the following paths when trying to open the tty
  943.      */
  944.     static char *prefix[] = { "", "/dev/", "/dev/tty", NULL };
  945.  
  946.     if ( old_protocol ){
  947.         old_nindy = 1;
  948.         return OninConnect( name, baudrate, brk, silent );
  949.     }
  950.  
  951.     quiet = silent;        /* Make global to this file */
  952.  
  953.     for ( i=0; prefix[i] != NULL; i++ ){
  954.         p = xmalloc(strlen(prefix[i]) + strlen(name) + 1 );
  955.         strcpy( p, prefix[i] );
  956.         strcat( p, name );
  957.         nindy_fd = open(p,O_RDWR);
  958.         if ( nindy_fd >= 0 ){
  959. #ifdef TIOCEXCL
  960.             /* Exclusive use mode (hp9000 does not support it) */
  961.             ioctl(nindy_fd,TIOCEXCL,NULL);
  962. #endif
  963.             if ( brk ){
  964.                 send_break( nindy_fd );
  965.             }
  966.  
  967.             brp = parse_baudrate( baudrate );
  968.             if ( brp == NULL ){
  969.                 say("Illegal baudrate %s ignored; using 9600\n",
  970.                                 baudrate);
  971.                 brp = parse_baudrate( "9600" );
  972.             }
  973.  
  974.             if ( !try_baudrate(nindy_fd,brp) ){
  975.                 autobaud(nindy_fd,brp);
  976.             }
  977.             tty_flush( nindy_fd );
  978.             say( "Connected to %s\n", p );
  979.             free(p);
  980.             break;
  981.         }
  982.         free(p);
  983.     }
  984.     return nindy_fd;
  985. }
  986.  
  987.  
  988.  
  989. /******************************************************************************
  990.  * ninDownload:
  991.  *    Ask NINDY to start up it's COFF downloader. Invoke 'sx' to perform
  992.  *    the XMODEM download from the host end.
  993.  *
  994.  *    Return 1 on success, 0 on failure.
  995.  ******************************************************************************/
  996.  
  997. #define XMODEM    "sx"    /* Name of xmodem transfer utility    */
  998.  
  999. int
  1000. ninDownload( fn, quiet )
  1001.     char *fn;        /* Stripped copy of object file            */
  1002.     int quiet;
  1003. {
  1004.     char *p;    /* Pointer to full pathname of sx utility    */
  1005.     int success;    /* Return value                    */
  1006.     int pid;    /* Process ID of xmodem transfer utility    */
  1007.     WAITTYPE w;    /* xmodem transfer completion status        */
  1008.     int wret;    /* Value returned by wait            */
  1009.     char buf[200];
  1010.  
  1011.  
  1012.     if ( old_nindy ){
  1013.         return OninDownload( fn, quiet );
  1014.     }
  1015.  
  1016.     /* Make sure the xmodem utility is findable.  This must be done before
  1017.      * we start up the NINDY end of the download (NINDY will hang if we
  1018.      * don't complete the download).
  1019.      */
  1020.     if ( ((p = exists("G960BIN",XMODEM,NULL,NULL,1)) == NULL)
  1021.     &&   ((p = exists("G960BASE","bin",XMODEM, NULL,1)) == NULL)
  1022. #ifdef HOST
  1023.     &&   ((p = exists(DEFAULT_BASE,HOST,"bin",XMODEM,0)) == NULL)
  1024. #endif
  1025.                                       ){
  1026.  
  1027.         fprintf(stderr,"Can't find '%s' download utility\n",XMODEM);
  1028.         fprintf(stderr,"Check env variables G960BIN and G960BASE\n");
  1029.         return 0;
  1030.     }
  1031.  
  1032.     if ( !quiet ){
  1033.         printf( "Downloading %s\n", fn );
  1034.     }
  1035.  
  1036.     /* Reset NINDY,  wait until "reset-complete" ack,
  1037.      * and start up the NINDY end of the download.
  1038.      */
  1039.     ninReset();
  1040.     putpkt((unsigned char *) "D", 1 );
  1041.  
  1042.     /* Invoke x-modem transfer, a separate process.  DON'T
  1043.      * use system() to do this -- under system V Unix, the
  1044.      * redirection of stdin/stdout causes the nindy tty to
  1045.      * lose all the transmission parameters we've set up.
  1046.      */
  1047.     success = 0;
  1048.  
  1049. #if defined(USG) && !defined(HAVE_VFORK)
  1050.     pid = fork ();
  1051. #else
  1052.     pid = vfork ();
  1053. #endif
  1054.     if ( pid == -1 ){
  1055.         perror( "Can't fork process:" );
  1056.  
  1057.     } else if ( pid == 0 ){        /* CHILD */
  1058.         dup2( nindy_fd, 0 );    /* Redirect stdin */
  1059.         dup2( nindy_fd, 1 );    /* Redirect stout */
  1060.         if ( quiet ){
  1061.             execl( p, p, "-q", fn, (char*)0 );
  1062.         } else {
  1063.             execl( p, p, fn, (char*)0 );
  1064.         }
  1065.         /* Don't get here unless execl fails */
  1066.         sprintf( buf, "Can't exec %s", p );
  1067.         perror( buf );
  1068.  
  1069.     } else {            /* PARENT */
  1070.         do {
  1071.             wret = wait(&w);
  1072.         } while ( wret != pid && wret != -1 );
  1073.  
  1074.         if ( wret == -1 ){
  1075.             perror( "Wait failed" );
  1076.         } else if (WIFEXITED(w) && (WEXITSTATUS(w) == 0)){
  1077.             success = 1;
  1078.         }
  1079.     }
  1080.     return success;
  1081. }
  1082.  
  1083.  
  1084. /******************************************************************************
  1085.  * ninGdbExit:
  1086.  *    Ask NINDY to leave GDB mode and print a NINDY prompt.
  1087.  ******************************************************************************/
  1088. ninGdbExit()
  1089. {
  1090.     if ( old_nindy ){
  1091.         OninGdbExit();
  1092.         return;
  1093.     }
  1094.         putpkt((unsigned char *) "E", 1 );
  1095. }
  1096.  
  1097.  
  1098. /******************************************************************************
  1099.  * ninGo:
  1100.  *    Ask NINDY to start or continue execution of an application program
  1101.  *    in it's memory at the current ip.
  1102.  ******************************************************************************/
  1103. ninGo( step_flag )
  1104.     int step_flag;    /* 1 => run in single-step mode */
  1105. {
  1106.     if ( old_nindy ){
  1107.         OninGo( step_flag );
  1108.         return;
  1109.     }
  1110.     putpkt((unsigned char *) (step_flag ? "s" : "c"), 1 );
  1111. }
  1112.  
  1113.  
  1114. /******************************************************************************
  1115.  * ninMemGet:
  1116.  *    Read a string of bytes from NINDY's address space (960 memory).
  1117.  ******************************************************************************/
  1118. ninMemGet(ninaddr, hostaddr, len)
  1119.      long ninaddr;    /* Source address, in the 960 memory space    */
  1120.      unsigned char *hostaddr;    /* Destination address, in our memory space */
  1121.      int len;        /* Number of bytes to read            */
  1122. {
  1123.     unsigned char buf[BUFSIZE+20];
  1124.     int cnt;        /* Number of bytes in next transfer    */
  1125.  
  1126.     if ( old_nindy ){
  1127.         OninMemGet(ninaddr, hostaddr, len);
  1128.         return;
  1129.     }
  1130.  
  1131.     for ( ; len > 0; len -= BUFSIZE ){
  1132.         cnt = len > BUFSIZE ? BUFSIZE : len;
  1133.  
  1134.         buf[0] = 'm';
  1135.         put_int( &buf[1], ninaddr );
  1136.         buf[5] = cnt & 0xff;
  1137.         buf[6] = (cnt>>8) & 0xff;
  1138.  
  1139.         send( buf, 7, hostaddr );
  1140.  
  1141.         ninaddr += cnt;
  1142.         hostaddr += cnt;
  1143.     }
  1144. }
  1145.  
  1146.  
  1147. /******************************************************************************
  1148.  * ninMemPut:
  1149.  *    Write a string of bytes into NINDY's address space (960 memory).
  1150.  ******************************************************************************/
  1151. ninMemPut( ninaddr, hostaddr, len )
  1152.      long ninaddr;    /* Destination address, in NINDY memory space    */
  1153.      unsigned char *hostaddr;    /* Source address, in our memory space    */
  1154.      int len;        /* Number of bytes to write            */
  1155. {
  1156.     unsigned char buf[BUFSIZE+20];
  1157.     int cnt;        /* Number of bytes in next transfer    */
  1158.  
  1159.     if ( old_nindy ){
  1160.         OninMemPut( ninaddr, hostaddr, len );
  1161.         return;
  1162.     }
  1163.     for ( ; len > 0; len -= BUFSIZE ){
  1164.         cnt = len > BUFSIZE ? BUFSIZE : len;
  1165.  
  1166.         buf[0] = 'M';
  1167.         put_int( &buf[1], ninaddr );
  1168.         bcopy( hostaddr, buf+5, cnt );
  1169.         send( buf, cnt+5, NULL );
  1170.  
  1171.         ninaddr += cnt;
  1172.         hostaddr += cnt;
  1173.     }
  1174. }
  1175.  
  1176. /******************************************************************************
  1177.  * ninRegGet:
  1178.  *    Retrieve the contents of a 960 register, and return them as a long
  1179.  *    in host byte order.
  1180.  *
  1181.  *    THIS ROUTINE CAN ONLY BE USED TO READ THE LOCAL, GLOBAL, AND
  1182.  *    ip/ac/pc/tc REGISTERS.
  1183.  *
  1184.  ******************************************************************************/
  1185. long
  1186. ninRegGet( regname )
  1187.     char *regname;    /* Register name recognized by NINDY, subject to the
  1188.              * above limitations.
  1189.              */
  1190. {
  1191.     unsigned char outbuf[10];
  1192.     unsigned char inbuf[20];
  1193.  
  1194.     if ( old_nindy ){
  1195.         return OninRegGet( regname );
  1196.     }
  1197.  
  1198.     sprintf( outbuf, "u%s:", regname );
  1199.     send( outbuf, strlen(outbuf), inbuf );
  1200.     return get_int(inbuf);
  1201. }
  1202.  
  1203. /******************************************************************************
  1204.  * ninRegPut:
  1205.  *    Set the contents of a 960 register.
  1206.  *
  1207.  *    THIS ROUTINE CAN ONLY BE USED TO SET THE LOCAL, GLOBAL, AND
  1208.  *    ip/ac/pc/tc REGISTERS.
  1209.  *
  1210.  ******************************************************************************/
  1211. ninRegPut( regname, val )
  1212.     char *regname;    /* Register name recognized by NINDY, subject to the
  1213.              * above limitations.
  1214.              */
  1215.     long val;        /* New contents of register, in host byte-order    */
  1216. {
  1217.     unsigned char buf[20];
  1218.     int len;
  1219.  
  1220.     if ( old_nindy ){
  1221.         OninRegPut( regname, val );
  1222.         return;
  1223.     }
  1224.  
  1225.     sprintf( buf, "U%s:", regname );
  1226.     len = strlen(buf);
  1227.     put_int( &buf[len], val );
  1228.     send( buf, len+4, NULL );
  1229. }
  1230.  
  1231. /******************************************************************************
  1232.  * ninRegsGet:
  1233.  *    Get a dump of the contents of the entire 960 register set.  The
  1234.  *    individual registers appear in the dump in the following order:
  1235.  *
  1236.  *        pfp  sp   rip  r3   r4   r5   r6   r7 
  1237.  *        r8   r9   r10  r11  r12  r13  r14  r15 
  1238.  *        g0   g1   g2   g3   g4   g5   g6   g7 
  1239.  *        g8   g9   g10  g11  g12  g13  g14  fp 
  1240.  *        pc   ac   ip   tc   fp0  fp1  fp2  fp3
  1241.  *
  1242.  *    Each individual register comprises exactly 4 bytes, except for
  1243.  *    fp0-fp3, which are 8 bytes.  All register values are in 960
  1244.  *    (little-endian) byte order.
  1245.  *
  1246.  ******************************************************************************/
  1247. ninRegsGet( regp )
  1248.     unsigned char *regp;        /* Where to place the register dump */
  1249. {
  1250.     if ( old_nindy ){
  1251.         OninRegsGet( regp );
  1252.         return;
  1253.     }
  1254.     send( (unsigned char *) "r", 1, regp );
  1255. }
  1256.  
  1257.  
  1258. /******************************************************************************
  1259.  * ninRegsPut:
  1260.  *    Initialize the entire 960 register set to a specified set of values.
  1261.  *    The format of the register value data should be the same as that
  1262.  *    returned by ninRegsGet.
  1263.  *
  1264.  * WARNING:
  1265.  *    All register values must be in 960 (little-endian) byte order.
  1266.  *
  1267.  ******************************************************************************/
  1268. ninRegsPut( regp )
  1269.     char *regp;        /* Pointer to desired values of registers */
  1270. {
  1271.     unsigned char buf[NINDY_REGISTER_BYTES+10];
  1272.  
  1273.     if ( old_nindy ){
  1274.         OninRegsPut( regp );
  1275.         return;
  1276.     }
  1277.  
  1278.     buf[0] = 'R';
  1279.     bcopy( regp, buf+1, NINDY_REGISTER_BYTES );
  1280.     send( buf, NINDY_REGISTER_BYTES+1, NULL );
  1281. }
  1282.  
  1283.  
  1284. /******************************************************************************
  1285.  * ninReset:
  1286.  *      Ask NINDY to perform a soft reset; wait for the reset to complete.
  1287.  *
  1288.  ******************************************************************************/
  1289. ninReset()
  1290. {
  1291.     unsigned char ack;
  1292.  
  1293.     if ( old_nindy ){
  1294.         OninReset();
  1295.         return;
  1296.     }
  1297.  
  1298.     while (1){
  1299.         putpkt((unsigned char *) "X", 1 );
  1300.         while (1){
  1301.             if ( !rdnin(&ack,1,5) ){
  1302.                 /* Timed out */
  1303.                 break;        /* Resend */
  1304.             }
  1305.             if ( ack == '+' ){
  1306.                 return;
  1307.             }
  1308.         }
  1309.     }
  1310. }
  1311.  
  1312.  
  1313. /******************************************************************************
  1314.  * ninSrq:
  1315.  *    Assume NINDY has stopped execution of the 960 application program in
  1316.  *    order to process a host service request (srq).  Ask NINDY for the
  1317.  *    srq arguments, perform the requested service, and send an "srq
  1318.  *    complete" message so NINDY will return control to the application.
  1319.  *
  1320.  ******************************************************************************/
  1321. ninSrq()
  1322. {
  1323.     unsigned char buf[BUFSIZE];
  1324.     int retcode;
  1325.     unsigned char srqnum;
  1326.     int i;
  1327.     int offset;
  1328.     int arg[MAX_SRQ_ARGS];
  1329.  
  1330.     if ( old_nindy ){
  1331.         OninSrq();
  1332.         return;
  1333.     }
  1334.  
  1335.  
  1336.     /* Get srq number and arguments
  1337.      */
  1338.     send((unsigned char *) "!", 1, buf );
  1339.  
  1340.     srqnum = buf[0];
  1341.     for  ( i=0, offset=1; i < MAX_SRQ_ARGS; i++, offset+=4 ){
  1342.         arg[i] = get_int(&buf[offset]);
  1343.     }
  1344.  
  1345.     /* Process Srq
  1346.      */
  1347.     switch( srqnum ){
  1348.     case BS_CLOSE:
  1349.         /* args: file descriptor */
  1350.         if ( arg[0] > 2 ){
  1351.             retcode = close( arg[0] );
  1352.         } else {
  1353.             retcode = 0;
  1354.         }
  1355.         break;
  1356.     case BS_CREAT:
  1357.         /* args: filename, mode */
  1358.         ninStrGet( arg[0], buf );
  1359.         retcode = creat(buf,arg[1]);
  1360.         break;
  1361.     case BS_OPEN:
  1362.         /* args: filename, flags, mode */
  1363.         ninStrGet( arg[0], buf );
  1364.         retcode = open(buf,arg[1],arg[2]);
  1365.         break;
  1366.     case BS_READ:
  1367.         /* args: file descriptor, buffer, count */
  1368.         retcode = read(arg[0],buf,arg[2]);
  1369.         if ( retcode > 0 ){
  1370.             ninMemPut( arg[1], buf, retcode );
  1371.         }
  1372.         break;
  1373.     case BS_SEEK:
  1374.         /* args: file descriptor, offset, whence */
  1375.         retcode = lseek(arg[0],arg[1],arg[2]);
  1376.         break;
  1377.     case BS_WRITE:
  1378.         /* args: file descriptor, buffer, count */
  1379.         ninMemGet( arg[1], buf, arg[2] );
  1380.         retcode = write(arg[0],buf,arg[2]);
  1381.         break;
  1382.     default:
  1383.         retcode = ERROR;
  1384.         break;
  1385.     }
  1386.  
  1387.     /* Send request termination status to NINDY
  1388.      */
  1389.     buf[0] = 'e';
  1390.     put_int( &buf[1], retcode );
  1391.     send( buf, 5, NULL );
  1392. }
  1393.  
  1394.  
  1395. /******************************************************************************
  1396.  * ninStopWhy:
  1397.  *    Assume the application program has stopped (i.e., a DLE was received
  1398.  *    from NINDY).  Ask NINDY for status information describing the
  1399.  *    reason for the halt.
  1400.  *
  1401.  *    Returns a non-zero value if the user program has exited, 0 otherwise.
  1402.  *    Also returns the following information, through passed pointers:
  1403.  *           - why: an exit code if program the exited; otherwise the reason
  1404.  *            why the program halted (see stop.h for values).
  1405.  *        - contents of register ip (little-endian byte order)
  1406.  *        - contents of register sp (little-endian byte order)
  1407.  *        - contents of register fp (little-endian byte order)
  1408.  ******************************************************************************/
  1409. char
  1410. ninStopWhy( whyp, ipp, fpp, spp )
  1411.     unsigned char *whyp; /* Return the 'why' code through this pointer    */
  1412.     long *ipp;    /* Return contents of register ip through this pointer    */
  1413.     long *fpp;    /* Return contents of register fp through this pointer    */
  1414.     long *spp;    /* Return contents of register sp through this pointer    */
  1415. {
  1416.     unsigned char buf[30];
  1417.     extern char OninStopWhy ();
  1418.  
  1419.     if ( old_nindy ){
  1420.         return OninStopWhy( whyp, ipp, fpp, spp );
  1421.     }
  1422.     send((unsigned char *) "?", 1, buf );
  1423.  
  1424.     *whyp = buf[1];
  1425.     bcopy (&buf[2],  (char *)ipp, sizeof (*ipp));
  1426.     bcopy (&buf[6],  (char *)fpp, sizeof (*ipp));
  1427.     bcopy (&buf[10], (char *)spp, sizeof (*ipp));
  1428.     return buf[0];
  1429. }
  1430.  
  1431. /******************************************************************************
  1432.  * ninStrGet:
  1433.  *    Read a '\0'-terminated string of data out of the 960 memory space.
  1434.  *
  1435.  ******************************************************************************/
  1436. static
  1437. ninStrGet( ninaddr, hostaddr )
  1438.      unsigned long ninaddr;    /* Address of string in NINDY memory space */
  1439.      unsigned char *hostaddr;    /* Address of the buffer to which string should
  1440.                  *    be copied.
  1441.                  */
  1442. {
  1443.     unsigned char cmd[5];
  1444.  
  1445.     cmd[0] = '"';
  1446.     put_int( &cmd[1], ninaddr );
  1447.     send( cmd, 5, hostaddr );
  1448. }
  1449.  
  1450. /******************************************************************************
  1451.  * ninVersion:
  1452.  *    Ask NINDY for version information about itself.
  1453.  *    The information is sent as an ascii string in the form "x.xx,<arch>",
  1454.  *    where,
  1455.  *        x.xx    is the version number
  1456.  *        <arch>    is the processor architecture: "KA", "KB", "MC", "CA" *
  1457.  *
  1458.  ******************************************************************************/
  1459. int
  1460. ninVersion( p )
  1461.      unsigned char *p;        /* Where to place version string */
  1462. {
  1463.  
  1464.     if ( old_nindy ){
  1465.         return OninVersion( p );
  1466.     }
  1467.     send((unsigned char *) "v", 1, p );
  1468.     return strlen(p);
  1469. }
  1470.