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 / Onindy.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-12  |  31.1 KB  |  1,146 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: Onindy.c,v 1.1.1.1 1991/03/28 16:20:43 rich Exp $";
  27.  
  28. /******************************************************************************
  29.  *
  30.  *             NINDY INTERFACE ROUTINES
  31.  *
  32.  * This version of the NINDY interface routines supports NINDY versions
  33.  * 2.13 and older.  The older versions used a hex communication protocol,
  34.  * instead of the (faster) current binary protocol.   These routines have
  35.  * been renamed by prepending the letter 'O' to their names, to avoid
  36.  * conflict with the current version.  The old versions are kept only for
  37.  * backward compatibility, and well disappear in a future release.
  38.  *
  39.  ******************************************************************************/
  40.  
  41. #include <stdio.h>
  42. #include <sys/ioctl.h>
  43. #include <sys/types.h>    /* Needed by file.h on Sys V */
  44. #include <sys/file.h>
  45. #include <signal.h>
  46. #include <sys/stat.h>
  47. #include <fcntl.h>    /* Needed on Sys V */
  48. #include "defs.h" /* needed for xmalloc */
  49. #include "ttycntl.h"
  50. #include "block_io.h"
  51. #include "wait.h"
  52. #include "env.h"
  53.  
  54.  
  55. #ifdef USG
  56. #    include <unistd.h>
  57. #    include "sysv.h"
  58. #else    /* BSD */
  59. #    include "string.h"
  60. #endif
  61.  
  62. #ifndef TRUE
  63. #define TRUE    1
  64. #endif
  65.  
  66. #ifndef FALSE
  67. #define FALSE    0
  68. #endif
  69.  
  70. #ifndef ERROR
  71. #define ERROR    -1
  72. #endif
  73.  
  74. #define NINDY_REGISTER_BYTES ((36*4) + (4*8))
  75.  
  76. extern void free ();
  77.  
  78. static int quiet;    /* TRUE => stifle unnecessary messages */
  79. static int nindy_fd;    /* File descriptor of tty connected to 960/NINDY board*/
  80. static OninStrGet();
  81.  
  82.         /****************************
  83.          *                          *
  84.          *  MISCELLANEOUS UTILTIES  *
  85.          *                          *
  86.          ****************************/
  87.  
  88.  
  89. /******************************************************************************
  90.  * fromhex:
  91.  *    Convert a hex ascii digit h to a binary integer
  92.  ******************************************************************************/
  93. static
  94. int
  95. fromhex( h )
  96.     int h;
  97. {
  98.     if (h >= '0' && h <= '9'){
  99.         h -= '0';
  100.     } else if (h >= 'a' && h <= 'f'){
  101.         h -= 'a' - 10;
  102.     } else {
  103.         h = 0;
  104.     }
  105.     return (h & 0xff);
  106. }
  107.  
  108.  
  109. /******************************************************************************
  110.  * hexbin:
  111.  *    Convert a string of ASCII hex digits to a string of binary bytes.
  112.  ******************************************************************************/
  113. static
  114. hexbin( n, hexp, binp )
  115.     int n;        /* Number of bytes to convert (twice this many digits)*/
  116.     char *hexp;        /* Get hex from here        */
  117.     char *binp;        /* Put binary here        */
  118. {
  119.     while ( n-- ){
  120.         *binp++ = (fromhex(*hexp) << 4) | fromhex(*(hexp+1));
  121.         hexp += 2;
  122.     }
  123. }
  124.  
  125.  
  126. /******************************************************************************
  127.  * binhex:
  128.  *    Convert a string of binary bytes to a string of ASCII hex digits
  129.  ******************************************************************************/
  130. static
  131. binhex( n, binp, hexp )
  132.     int n;              /* Number of bytes to convert   */
  133.     char *binp;         /* Get binary from here         */
  134.     char *hexp;         /* Place hex here               */
  135. {
  136.     static char tohex[] = "0123456789abcdef";
  137.  
  138.         while ( n-- ){
  139.                 *hexp++ = tohex[ (*binp >> 4) & 0xf ];
  140.                 *hexp++ = tohex[ *binp & 0xf ];
  141.                 binp++;
  142.         }
  143. }
  144.  
  145. /******************************************************************************
  146.  * byte_order:
  147.  *    If the host byte order is different from 960 byte order (i.e., the
  148.  *    host is big-endian), reverse the bytes in the passed value;  otherwise,
  149.  *    return the passed value unchanged.
  150.  *
  151.  ******************************************************************************/
  152. static
  153. long
  154. byte_order( n )
  155.     long n;
  156. {
  157.     long rev;
  158.     int i;
  159.     static short test = 0x1234;
  160.  
  161.     if (*((char *) &test) == 0x12) {
  162.         /*
  163.          * Big-endian host, swap the bytes.
  164.          */
  165.         rev = 0;
  166.         for ( i = 0; i < sizeof(n); i++ ){
  167.             rev <<= 8;
  168.             rev |= n & 0xff;
  169.             n >>= 8;
  170.         }
  171.         n = rev;
  172.     }
  173.     return n;
  174. }
  175.  
  176. /******************************************************************************
  177.  * say:
  178.  *    This is a printf that takes at most two arguments (in addition to the
  179.  *    format string) and that outputs nothing if verbose output has been
  180.  *    suppressed.
  181.  ******************************************************************************/
  182. static
  183. say( fmt, arg1, arg2 )
  184.     char *fmt;
  185.     int arg1, arg2;
  186. {
  187.     if ( !quiet ){
  188.         printf( fmt, arg1, arg2 );
  189.         fflush( stdout );
  190.     }
  191. }
  192.  
  193. /******************************************************************************
  194.  * exists:
  195.  *    Creates a full pathname by concatenating up to three name components
  196.  *    onto a specified base name; optionally looks up the base name as a
  197.  *    runtime environment variable;  and checks to see if the file or
  198.  *    directory specified by the pathname actually exists.
  199.  *
  200.  *    Returns:  the full pathname if it exists, NULL otherwise.
  201.  *        (returned pathname is in malloc'd memory and must be freed
  202.  *        by caller).
  203.  *****************************************************************************/
  204. static
  205. char *
  206. exists( base, c1, c2, c3, env )
  207.     char *base;        /* Base directory of path */
  208.     char *c1, *c2, *c3;    /* Components (subdirectories and/or file name) to be
  209.              *    appended onto the base directory name.  One or
  210.              *    more may be omitted by passing NULL pointers.
  211.              */
  212.     int env;        /* If 1, '*base' is the name of an environment variable
  213.              *    to be examined for the base directory name;
  214.              *    otherwise, '*base' is the actual name of the
  215.              *    base directory.
  216.              */
  217. {
  218.     struct stat buf;/* For call to 'stat' -- never examined */
  219.     char *path;    /* Pointer to full pathname (malloc'd memory) */
  220.     int len;    /* Length of full pathname (incl. terminator) */
  221.     extern char *getenv();
  222.  
  223.  
  224.     if ( env ){
  225.         base = getenv( base );
  226.         if ( base == NULL ){
  227.             return NULL;
  228.         }
  229.     }
  230.  
  231.     len = strlen(base) + 4;
  232.             /* +4 for terminator and "/" before each component */
  233.     if ( c1 != NULL ){
  234.         len += strlen(c1);
  235.     }
  236.     if ( c2 != NULL ){
  237.         len += strlen(c2);
  238.     }
  239.     if ( c3 != NULL ){
  240.         len += strlen(c3);
  241.     }
  242.  
  243.     path = xmalloc( len );
  244.  
  245.     strcpy( path, base );
  246.     if ( c1 != NULL ){
  247.         strcat( path, "/" );
  248.         strcat( path, c1 );
  249.         if ( c2 != NULL ){
  250.             strcat( path, "/" );
  251.             strcat( path, c2 );
  252.             if ( c3 != NULL ){
  253.                 strcat( path, "/" );
  254.                 strcat( path, c3 );
  255.             }
  256.         }
  257.     }
  258.  
  259.     if ( stat(path,&buf) != 0 ){
  260.         free( path );
  261.         path = NULL;
  262.     }
  263.     return path;
  264. }
  265.  
  266.         /*****************************
  267.          *                           *
  268.          *  LOW-LEVEL COMMUNICATION  *
  269.          *                           *
  270.          *****************************/
  271.  
  272. /******************************************************************************
  273.  * readchar:
  274.  *    Wait for a character to come in on the NINDY tty, and return it.
  275.  ******************************************************************************/
  276. static
  277. readchar()
  278. {
  279.     unsigned char c;
  280.  
  281.     while (read(nindy_fd,&c,1) != 1){
  282.         ;
  283.     }
  284.     return c;
  285. }
  286.  
  287.  
  288. /******************************************************************************
  289.  * getpkt:
  290.  *    Read a packet from a remote NINDY, with error checking, and return
  291.  *    it in the indicated buffer.
  292.  ******************************************************************************/
  293. static
  294. getpkt (buf)
  295.      char *buf;
  296. {
  297.     unsigned char recv;    /* Checksum received        */
  298.     unsigned char csum;    /* Checksum calculated        */
  299.     char *bp;        /* Poointer into the buffer    */
  300.     int c;
  301.  
  302.     while (1){
  303.         csum = 0;
  304.         bp = buf;
  305.         while ( (c = readchar()) != '#' ){
  306.             *bp++ = c;
  307.             csum += c;
  308.         }
  309.         *bp = 0;
  310.  
  311.         recv = fromhex(readchar()) << 4;
  312.         recv |= fromhex(readchar());
  313.         if ( csum == recv ){
  314.             break;
  315.         }
  316.     
  317.         fprintf(stderr,
  318.             "Bad checksum (recv=0x%02x; calc=0x%02x); retrying\r\n",
  319.                                 recv, csum );
  320.         write (nindy_fd, "-", 1);
  321.     }
  322.  
  323.     write (nindy_fd, "+", 1);
  324. }
  325.  
  326.  
  327. /******************************************************************************
  328.  * putpkt:
  329.  *    Checksum and send a gdb command to a remote NINDY, and wait for
  330.  *    positive acknowledgement.
  331.  *
  332.  ******************************************************************************/
  333. static
  334. putpkt( cmd )
  335.     char *cmd;    /* Command to be sent, without lead ^P (\020)
  336.          * or trailing checksum
  337.          */
  338. {
  339.     char ack;    /* Response received from NINDY        */
  340.     char checksum[4];
  341.     char *p;
  342.     unsigned int s;
  343.     char resend;
  344.  
  345.     for ( s='\020', p=cmd; *p; p++ ){
  346.         s += *p;
  347.     }
  348.     sprintf( checksum, "#%02x",  s & 0xff );
  349.  
  350.     /* Send checksummed message over and over until we get a positive ack
  351.      */
  352.     resend = TRUE;
  353.     do {
  354.         if ( resend ){
  355.             write( nindy_fd, "\020", 1 );
  356.             write( nindy_fd, cmd, strlen(cmd) );
  357.             write( nindy_fd, checksum, strlen(checksum) );
  358.         }
  359.         if  ( read( nindy_fd, &ack, 1 ) != 1 ){
  360.             fprintf(stderr,"oink\n");
  361.         }
  362.         if ( ack == '-' ){
  363.             fprintf( stderr, "Remote NAK, resending\r\n" );
  364.             resend = TRUE;
  365.         } else if ( ack != '+' ){
  366.             fprintf( stderr, "Bad ACK, ignored: <%c>\r\n", ack );
  367.             resend = FALSE;
  368.         }
  369.     } while ( ack != '+' );
  370. }
  371.  
  372.  
  373.  
  374. /******************************************************************************
  375.  * send:
  376.  *    Send a message to a remote NINDY and return the reply in the same
  377.  *    buffer (clobbers the input message).  Check for error responses
  378.  *    as indicated by the second argument.
  379.  *
  380.  ******************************************************************************/
  381. static
  382. send( buf, ack_required )
  383.     char *buf;        /* Message to be sent to NINDY; replaced by
  384.              *    NINDY's response.
  385.              */
  386.     int ack_required;    /* TRUE means NINDY's response MUST be either "X00" (no
  387.              *    error) or an error code "Xnn".
  388.              * FALSE means the it's OK as long as it doesn't
  389.              *    begin with "Xnn".
  390.              */
  391. {
  392.     int errnum;
  393.     static char *errmsg[] = {
  394.         "",                        /* X00 */
  395.         "Buffer overflow",                /* X01 */
  396.         "Unknown command",                /* X02 */
  397.         "Wrong amount of data to load register(s)",    /* X03 */
  398.         "Missing command argument(s)",            /* X04 */
  399.         "Odd number of digits sent to load memory",    /* X05 */
  400.         "Unknown register name",            /* X06 */
  401.         "No such memory segment",            /* X07 */
  402.         "No breakpoint available",            /* X08 */
  403.         "Can't set requested baud rate",        /* X09 */
  404.     };
  405. #    define NUMERRS    ( sizeof(errmsg) / sizeof(errmsg[0]) )
  406.  
  407.     static char err0[] = "NINDY failed to acknowledge command: <%s>\r\n";
  408.     static char err1[] = "Unknown error response from NINDY: <%s>\r\n";
  409.     static char err2[] = "Error response %s from NINDY: %s\r\n";
  410.  
  411.     putpkt (buf);
  412.     getpkt (buf);
  413.  
  414.     if ( buf[0] != 'X' ){
  415.         if ( ack_required ){
  416.             fprintf( stderr, err0, buf );
  417.             abort();
  418.         }
  419.  
  420.     } else if ( strcmp(buf,"X00") ){
  421.         sscanf( &buf[1], "%x", &errnum );
  422.         if ( errnum > NUMERRS ){
  423.             fprintf( stderr, err1, buf );
  424.         } else{
  425.             fprintf( stderr, err2, buf, errmsg[errnum] );
  426.         }
  427.         abort();
  428.     }
  429. }
  430.  
  431.         /************************
  432.          *                      *
  433.          *  BAUD RATE ROUTINES  *
  434.          *                      *
  435.          ************************/
  436.  
  437. /* Table of baudrates known to be acceptable to NINDY.  Each baud rate
  438.  * appears both as character string and as a Unix baud rate constant.
  439.  */
  440. struct baudrate {
  441.     char *string;
  442.     int rate;
  443. };
  444.  
  445. static struct baudrate baudtab[] = {
  446.      "1200", B1200,
  447.      "2400", B2400,
  448.      "4800", B4800,
  449.      "9600", B9600,
  450.     "19200", B19200,
  451.     "38400", B38400,
  452.     NULL,    0        /* End of table */
  453. };
  454.  
  455.  
  456. /******************************************************************************
  457.  * parse_baudrate:
  458.  *    Look up the passed baud rate in the baudrate table.  If found, change
  459.  *    our internal record of the current baud rate, but don't do anything
  460.  *    about the tty just now.
  461.  *
  462.  *    Return pointer to baudrate structure on success, NULL on failure.
  463.  ******************************************************************************/
  464. static
  465. struct baudrate *
  466. parse_baudrate(s)
  467.     char *s;    /* Desired baud rate, as an ASCII (decimal) string */
  468. {
  469.     int i;
  470.  
  471.     for ( i=0; baudtab[i].string != NULL; i++ ){
  472.         if ( !strcmp(baudtab[i].string,s) ){
  473.             return &baudtab[i];
  474.         }
  475.     }
  476.     return NULL;
  477. }
  478.  
  479. /******************************************************************************
  480.  * try_baudrate:
  481.  *    Try speaking to NINDY via the specified file descriptor at the
  482.  *    specified baudrate.  Assume success it we can send an empty command
  483.  *    with a bogus checksum and receive a NAK (response of '-') back within
  484.  *    one second.
  485.  *
  486.  *    Return 1 on success, 0 on failure.
  487.  ******************************************************************************/
  488.  
  489. static int saw_alarm;
  490.  
  491. static void
  492. alarm_handler()
  493. {
  494.     saw_alarm = 1;
  495. }
  496.  
  497. static int
  498. try_baudrate( fd, brp )
  499.     int fd;
  500.     struct baudrate *brp;
  501. {
  502.     TTY_STRUCT tty;
  503.     char c;
  504.     int n;
  505.     void (*old_alarm)();    /* Save alarm signal handler here on entry */
  506.     
  507.  
  508.     /* Set specified baud rate and flush all pending input */
  509.     ioctl( fd, TIOCGETP, &tty );
  510.     TTY_REMOTE( tty, brp->rate );
  511.     ioctl( fd, TIOCSETP, &tty );
  512.     tty_flush( fd );
  513.  
  514.     /* Send bogus command */
  515.     write( fd, "\020#00", 4 );
  516.  
  517.     /* Wait until reponse comes back or one second passes */
  518.     old_alarm = signal( SIGALRM,alarm_handler );
  519.     saw_alarm = 0;
  520.     alarm(1);
  521.     do {
  522.         n = 1;
  523.         TTY_NBREAD(fd,n,&c);
  524.     } while ( n<=0 && !saw_alarm );
  525.  
  526.     /* Turn off alarm */
  527.     alarm(0);
  528.     signal( SIGALRM,old_alarm );
  529.  
  530.     /* Did we get a '-' back ? */
  531.     if ( (n > 0) && (c == '-') ){
  532.         return 1;
  533.     }
  534.     return 0;
  535. }
  536.  
  537. /******************************************************************************
  538.  * autobaud:
  539.  *    Get NINDY talking over the specified file descriptor at the specified
  540.  *    baud rate.  First see if NINDY's already talking at 'baudrate'.  If
  541.  *    not, run through all the legal baudrates in 'baudtab' until one works,
  542.  *    and then tell NINDY to talk at 'baudrate' instead.
  543.  ******************************************************************************/
  544. static
  545. autobaud( fd, brp )
  546.     int fd;
  547.     struct baudrate *brp;
  548. {
  549.     int i;
  550.     TTY_STRUCT tty;
  551.  
  552.  
  553.     say("NINDY at wrong baud rate? Trying to autobaud...\n");
  554.     i = 0;
  555.     while ( 1 ){
  556.         say( "\r%s...   ", baudtab[i].string );
  557.         if ( try_baudrate(fd,&baudtab[i]) ){
  558.             break;
  559.         }
  560.         if ( baudtab[++i].string == NULL ){
  561.             /* End of table -- wraparound */
  562.             i = 0;
  563.             say("\nAutobaud failed. Trying again...\n");
  564.         }
  565.     }
  566.  
  567.     /* Found NINDY's current baud rate;  now change it.
  568.      */
  569.     say("Changing NINDY baudrate to %s\n", brp->string);
  570.     OninBaud( brp->string );
  571.  
  572.     /* Change our baud rate back to rate to which we just set NINDY.
  573.      */
  574.     ioctl( fd, TIOCGETP, &tty );
  575.     TTY_REMOTE( tty, brp->rate );
  576.     ioctl( fd, TIOCSETP, &tty );
  577. }
  578.  
  579.         /**********************************
  580.          *                  *
  581.          *   NINDY INTERFACE ROUTINES      *
  582.          *                                  *
  583.          * ninConnect *MUST* be the first *
  584.          * one of these routines called.  *
  585.          **********************************/
  586.  
  587.  
  588. /******************************************************************************
  589.  * ninBaud:
  590.  *    Ask NINDY to change the baud rate on its serial port.
  591.  *    Assumes we know the baud rate at which NINDY's currently talking.
  592.  ******************************************************************************/
  593. OninBaud( baudrate )
  594.     char *baudrate;    /* Desired baud rate, as a string of ASCII decimal
  595.              * digits.
  596.              */
  597. {
  598.     char buf[100];        /* Message buffer    */
  599.     char *p;        /* Pointer into buffer    */
  600.     unsigned char csum;    /* Calculated checksum    */
  601.  
  602.     tty_flush( nindy_fd );
  603.  
  604.     /* Can't use putpkt() because after the baudrate change
  605.      * NINDY's ack/nak will look like gibberish.
  606.      */
  607.     for ( p=baudrate, csum=020+'z'; *p; p++ ){
  608.         csum += *p;
  609.     }
  610.     sprintf( buf, "\020z%s#%02x", baudrate, csum );
  611.     write( nindy_fd, buf, strlen(buf) );
  612. }
  613.  
  614.  
  615. /******************************************************************************
  616.  * ninBptDel:
  617.  *    Ask NINDY to delete the specified type of *hardware* breakpoint at
  618.  *    the specified address.  If the 'addr' is -1, all breakpoints of
  619.  *    the specified type are deleted.
  620.  ******************************************************************************/
  621. OninBptDel( addr, data )
  622.     long addr;    /* Address in 960 memory    */
  623.     int data;    /* '1' => data bkpt, '0' => instruction breakpoint */
  624. {
  625.     char buf[100];
  626.  
  627.     if ( addr == -1 ){
  628.         sprintf( buf, "b%c", data ? '1' : '0' );
  629.     } else {
  630.         sprintf( buf, "b%c%x", data ? '1' : '0', addr );
  631.     }
  632.     return send( buf, FALSE );
  633. }
  634.  
  635.  
  636. /******************************************************************************
  637.  * ninBptSet:
  638.  *    Ask NINDY to set the specified type of *hardware* breakpoint at
  639.  *    the specified address.
  640.  ******************************************************************************/
  641. OninBptSet( addr, data )
  642.     long addr;    /* Address in 960 memory    */
  643.     int data;    /* '1' => data bkpt, '0' => instruction breakpoint */
  644. {
  645.     char buf[100];
  646.  
  647.     sprintf( buf, "B%c%x", data ? '1' : '0', addr );
  648.     return send( buf, FALSE );
  649. }
  650.  
  651.  
  652. /******************************************************************************
  653.  * ninConnect:
  654.  *    Open the specified tty.  Get communications working at the specified
  655.  *    Flush any pending I/O on the tty.
  656.  *
  657.  *    Return the file descriptor, or -1 on failure.
  658.  ******************************************************************************/
  659. int
  660. OninConnect( name, baudrate, brk, silent )
  661.     char *name;        /* "/dev/ttyXX" to be opened            */
  662.     char *baudrate;/* baud rate: a string of ascii decimal digits (eg,"9600")*/
  663.     int brk;        /* 1 => send break to tty first thing after opening it*/
  664.     int silent;        /* 1 => stifle unnecessary messages when talking to 
  665.              *    this tty.
  666.              */
  667. {
  668.     int i;
  669.     char *p;
  670.     struct baudrate *brp;
  671.  
  672.     /* We will try each of the following paths when trying to open the tty
  673.      */
  674.     static char *prefix[] = { "", "/dev/", "/dev/tty", NULL };
  675.  
  676.     quiet = silent;        /* Make global to this file */
  677.  
  678.     for ( i=0; prefix[i] != NULL; i++ ){
  679.         p = xmalloc(strlen(prefix[i]) + strlen(name) + 1 );
  680.         strcpy( p, prefix[i] );
  681.         strcat( p, name );
  682.         nindy_fd = open(p,O_RDWR);
  683.         if ( nindy_fd >= 0 ){
  684. #ifdef TIOCEXCL
  685.             /* Exclusive use mode (hp9000 does not support it) */
  686.             ioctl(nindy_fd,TIOCEXCL,NULL);
  687. #endif
  688.             if ( brk ){
  689.                 send_break( nindy_fd );
  690.             }
  691.  
  692.             brp = parse_baudrate( baudrate );
  693.             if ( brp == NULL ){
  694.                 say("Illegal baudrate %s ignored; using 9600\n",
  695.                                 baudrate);
  696.                 brp = parse_baudrate( "9600" );
  697.             }
  698.  
  699.             if ( !try_baudrate(nindy_fd,brp) ){
  700.                 autobaud(nindy_fd,brp);
  701.             }
  702.             tty_flush( nindy_fd );
  703.             say( "Connected to %s\n", p );
  704.             free(p);
  705.             break;
  706.         }
  707.         free(p);
  708.     }
  709.     return nindy_fd;
  710. }
  711.  
  712.  
  713.  
  714. /******************************************************************************
  715.  * ninDownload:
  716.  *    Ask NINDY to start up it's COFF downloader. Invoke 'sx' to perform
  717.  *    the XMODEM download from the host end.
  718.  *
  719.  *    Return 1 on success, 0 on failure.
  720.  ******************************************************************************/
  721.  
  722. #define XMODEM    "sx"    /* Name of xmodem transfer utility    */
  723.  
  724. int
  725. OninDownload( fn, quiet )
  726.     char *fn;        /* Stripped copy of object file            */
  727.     int quiet;
  728. {
  729.     char *p;    /* Pointer to full pathname of sx utility    */
  730.     int success;    /* Return value                    */
  731.     int pid;    /* Process ID of xmodem transfer utility    */
  732.     WAITTYPE w;    /* xmodem transfer completion status        */
  733.     char buf[200];
  734.  
  735.  
  736.     /* Make sure the xmodem utility is findable.  This must be done before
  737.      * we start up the NINDY end of the download (NINDY will hang if we
  738.      * don't complete the download).
  739.      */
  740.     if ( ((p = exists("G960BIN",XMODEM,NULL,NULL,1)) == NULL)
  741.     &&   ((p = exists("G960BASE","bin",XMODEM, NULL,1)) == NULL)
  742. #ifdef HOST
  743.     &&   ((p = exists(DEFAULT_BASE,HOST,"bin",XMODEM,0)) == NULL)
  744. #endif
  745.                                       ){
  746.  
  747.         fprintf(stderr,"Can't find '%s' download utility\n",XMODEM);
  748.         fprintf(stderr,"Check env variables G960BIN and G960BASE\n");
  749.         return 0;
  750.     }
  751.  
  752.     if ( !quiet ){
  753.         printf( "Downloading %s\n", fn );
  754.     }
  755.  
  756.     /* Reset NINDY,  wait until "reset-complete" ack,
  757.      * and start up the NINDY end of the download.
  758.      */
  759.     OninReset();
  760.     putpkt( "D" );
  761.  
  762.     /* Invoke x-modem transfer, a separate process.  DON'T
  763.      * use system() to do this -- under system V Unix, the
  764.      * redirection of stdin/stdout causes the nindy tty to
  765.      * lose all the transmission parameters we've set up.
  766.      */
  767.     success = 0;
  768.  
  769.     pid = fork();
  770.     if ( pid == -1 ){
  771.         perror( "Can't fork process:" );
  772.  
  773.     } else if ( pid == 0 ){        /* CHILD */
  774.         dup2( nindy_fd, 0 );    /* Redirect stdin */
  775.         dup2( nindy_fd, 1 );    /* Redirect stout */
  776.         if ( quiet ){
  777.             execl( p, p, "-q", fn, (char*)0 );
  778.         } else {
  779.             execl( p, p, fn, (char*)0 );
  780.         }
  781.         /* Don't get here unless execl fails */
  782.         sprintf( buf, "Can't exec %s", p );
  783.         perror( buf );
  784.  
  785.     } else {            /* PARENT */
  786.         if ( wait(&w) == -1 ){
  787.             perror( "Wait failed" );
  788.         } else if (WIFEXITED(w) && (WEXITSTATUS(w) == 0)){
  789.             success = 1;
  790.         }
  791.     }
  792.     return success;
  793. }
  794.  
  795.  
  796. /******************************************************************************
  797.  * ninGdbExit:
  798.  *    Ask NINDY to leave GDB mode and print a NINDY prompt.
  799.  *    Since it'll no longer be in GDB mode, don't wait for a response.
  800.  ******************************************************************************/
  801. OninGdbExit()
  802. {
  803.         putpkt( "E" );
  804. }
  805.  
  806.  
  807. /******************************************************************************
  808.  * ninGo:
  809.  *    Ask NINDY to start or continue execution of an application program
  810.  *    in it's memory at the current ip.
  811.  ******************************************************************************/
  812. OninGo( step_flag )
  813.     int step_flag;    /* 1 => run in single-step mode */
  814. {
  815.     putpkt( step_flag ? "s" : "c" );
  816. }
  817.  
  818.  
  819. /******************************************************************************
  820.  * ninMemGet:
  821.  *    Read a string of bytes from NINDY's address space (960 memory).
  822.  ******************************************************************************/
  823. OninMemGet(ninaddr, hostaddr, len)
  824.      long ninaddr;    /* Source address, in the 960 memory space    */
  825.      char *hostaddr;    /* Destination address, in our memory space    */
  826.      int len;        /* Number of bytes to read            */
  827. {
  828.     char buf[2*BUFSIZE+20];    /* Buffer: hex in, binary out        */
  829.     int cnt;        /* Number of bytes in next transfer    */
  830.  
  831.     for ( ; len > 0; len -= BUFSIZE ){
  832.         cnt = len > BUFSIZE ? BUFSIZE : len;
  833.  
  834.         sprintf( buf, "m%x,%x", ninaddr, cnt );
  835.         send( buf, FALSE );
  836.         hexbin( cnt, buf, hostaddr );
  837.  
  838.         ninaddr += cnt;
  839.         hostaddr += cnt;
  840.     }
  841. }
  842.  
  843.  
  844. /******************************************************************************
  845.  * ninMemPut:
  846.  *    Write a string of bytes into NINDY's address space (960 memory).
  847.  ******************************************************************************/
  848. OninMemPut( destaddr, srcaddr, len )
  849.      long destaddr;    /* Destination address, in NINDY memory space    */
  850.      char *srcaddr;    /* Source address, in our memory space        */
  851.      int len;        /* Number of bytes to write            */
  852. {
  853.     char buf[2*BUFSIZE+20];    /* Buffer: binary in, hex out        */
  854.     char *p;        /* Pointer into buffer            */
  855.     int cnt;        /* Number of bytes in next transfer    */
  856.  
  857.     for ( ; len > 0; len -= BUFSIZE ){
  858.         cnt = len > BUFSIZE ? BUFSIZE : len;
  859.  
  860.         sprintf( buf, "M%x,", destaddr );
  861.         p = buf + strlen(buf);
  862.         binhex( cnt, srcaddr, p );
  863.         *(p+(2*cnt)) = '\0';
  864.         send( buf, TRUE );
  865.  
  866.         srcaddr += cnt;
  867.         destaddr += cnt;
  868.     }
  869. }
  870.  
  871. /******************************************************************************
  872.  * ninRegGet:
  873.  *    Retrieve the contents of a 960 register, and return them as a long
  874.  *    in host byte order.
  875.  *
  876.  *    THIS ROUTINE CAN ONLY BE USED TO READ THE LOCAL, GLOBAL, AND
  877.  *    ip/ac/pc/tc REGISTERS.
  878.  *
  879.  ******************************************************************************/
  880. long
  881. OninRegGet( regname )
  882.     char *regname;    /* Register name recognized by NINDY, subject to the
  883.              * above limitations.
  884.              */
  885. {
  886.     char buf[200];
  887.     long val;
  888.  
  889.     sprintf( buf, "u%s", regname );
  890.     send( buf, FALSE );
  891.     hexbin( 4, buf, (char *)&val );
  892.     return byte_order(val);
  893. }
  894.  
  895. /******************************************************************************
  896.  * ninRegPut:
  897.  *    Set the contents of a 960 register.
  898.  *
  899.  *    THIS ROUTINE CAN ONLY BE USED TO SET THE LOCAL, GLOBAL, AND
  900.  *    ip/ac/pc/tc REGISTERS.
  901.  *
  902.  ******************************************************************************/
  903. OninRegPut( regname, val )
  904.     char *regname;    /* Register name recognized by NINDY, subject to the
  905.              * above limitations.
  906.              */
  907.     long val;        /* New contents of register, in host byte-order    */
  908. {
  909.     char buf[200];
  910.  
  911.     sprintf( buf, "U%s,%08x", regname, byte_order(val) );
  912.     send( buf, TRUE );
  913. }
  914.  
  915. /******************************************************************************
  916.  * ninRegsGet:
  917.  *    Get a dump of the contents of the entire 960 register set.  The
  918.  *    individual registers appear in the dump in the following order:
  919.  *
  920.  *        pfp  sp   rip  r3   r4   r5   r6   r7 
  921.  *        r8   r9   r10  r11  r12  r13  r14  r15 
  922.  *        g0   g1   g2   g3   g4   g5   g6   g7 
  923.  *        g8   g9   g10  g11  g12  g13  g14  fp 
  924.  *        pc   ac   ip   tc   fp0  fp1  fp2  fp3
  925.  *
  926.  *    Each individual register comprises exactly 4 bytes, except for
  927.  *    fp0-fp3, which are 8 bytes.
  928.  *
  929.  * WARNING:
  930.  *    Each register value is in 960 (little-endian) byte order.
  931.  *
  932.  ******************************************************************************/
  933. OninRegsGet( regp )
  934.     char *regp;        /* Where to place the register dump */
  935. {
  936.     char buf[(2*NINDY_REGISTER_BYTES)+10];   /* Registers in ASCII hex */
  937.  
  938.     strcpy( buf, "r" );
  939.     send( buf, FALSE );
  940.     hexbin( NINDY_REGISTER_BYTES, buf, regp );
  941. }
  942.  
  943. /******************************************************************************
  944.  * ninRegsPut:
  945.  *    Initialize the entire 960 register set to a specified set of values.
  946.  *    The format of the register value data should be the same as that
  947.  *    returned by ninRegsGet.
  948.  *
  949.  * WARNING:
  950.  *    Each register value should be in 960 (little-endian) byte order.
  951.  *
  952.  ******************************************************************************/
  953. OninRegsPut( regp )
  954.     char *regp;        /* Pointer to desired values of registers */
  955. {
  956.     char buf[(2*NINDY_REGISTER_BYTES)+10];   /* Registers in ASCII hex */
  957.  
  958.     buf[0] = 'R';
  959.     binhex( NINDY_REGISTER_BYTES, regp, buf+1 );
  960.     buf[ (2*NINDY_REGISTER_BYTES)+1 ] = '\0';
  961.  
  962.     send( buf, TRUE );
  963. }
  964.  
  965.  
  966. /******************************************************************************
  967.  * ninReset:
  968.  *      Ask NINDY to perform a soft reset; wait for the reset to complete.
  969.  ******************************************************************************/
  970. OninReset()
  971. {
  972.  
  973.     putpkt( "X" );
  974.     while ( readchar() != '+' ){
  975.         ;
  976.     }
  977. }
  978.  
  979.  
  980. /******************************************************************************
  981.  * ninSrq:
  982.  *    Assume NINDY has stopped execution of the 960 application program in
  983.  *    order to process a host service request (srq).  Ask NINDY for the
  984.  *    srq arguments, perform the requested service, and send an "srq
  985.  *    complete" message so NINDY will return control to the application.
  986.  *
  987.  ******************************************************************************/
  988. OninSrq()
  989. {
  990.     char buf[BUFSIZE];
  991.     int retcode;
  992.     unsigned char srqnum;
  993.     char *p;
  994.     char *argp;
  995.     int nargs;
  996.     int arg[MAX_SRQ_ARGS];
  997.  
  998.  
  999.     /* Get srq number and arguments
  1000.      */
  1001.     strcpy( buf, "!" );
  1002.     send( buf, FALSE );
  1003.     hexbin( 1, buf, (char *)&srqnum );
  1004.  
  1005.     /* Set up array of pointers the each of the individual
  1006.      * comma-separated args
  1007.      */
  1008.     nargs=0;
  1009.     argp = p = buf+2;
  1010.         while ( 1 ){
  1011.                 while ( *p != ',' && *p != '\0' ){
  1012.                         p++;
  1013.                 }
  1014.                 sscanf( argp, "%x", &arg[nargs++] );
  1015.                 if ( *p == '\0' || nargs == MAX_SRQ_ARGS ){
  1016.                         break;
  1017.                 }
  1018.                 argp = ++p;
  1019.         }
  1020.  
  1021.     /* Process Srq
  1022.      */
  1023.     switch( srqnum ){
  1024.     case BS_CLOSE:
  1025.         /* args: file descriptor */
  1026.         if ( arg[0] > 2 ){
  1027.             retcode = close( arg[0] );
  1028.         } else {
  1029.             retcode = 0;
  1030.         }
  1031.         break;
  1032.     case BS_CREAT:
  1033.         /* args: filename, mode */
  1034.         OninStrGet( arg[0], buf );
  1035.         retcode = creat(buf,arg[1]);
  1036.         break;
  1037.     case BS_OPEN:
  1038.         /* args: filename, flags, mode */
  1039.         OninStrGet( arg[0], buf );
  1040.         retcode = open(buf,arg[1],arg[2]);
  1041.         break;
  1042.     case BS_READ:
  1043.         /* args: file descriptor, buffer, count */
  1044.         retcode = read(arg[0],buf,arg[2]);
  1045.         if ( retcode > 0 ){
  1046.             OninMemPut( arg[1], buf, retcode );
  1047.         }
  1048.         break;
  1049.     case BS_SEEK:
  1050.         /* args: file descriptor, offset, whence */
  1051.         retcode = lseek(arg[0],arg[1],arg[2]);
  1052.         break;
  1053.     case BS_WRITE:
  1054.         /* args: file descriptor, buffer, count */
  1055.         OninMemGet( arg[1], buf, arg[2] );
  1056.         retcode = write(arg[0],buf,arg[2]);
  1057.         break;
  1058.     default:
  1059.         retcode = ERROR;
  1060.         break;
  1061.     }
  1062.  
  1063.     /* Tell NINDY to continue
  1064.      */
  1065.     sprintf( buf, "e%x", retcode );
  1066.     send( buf, TRUE );
  1067. }
  1068.  
  1069.  
  1070. /******************************************************************************
  1071.  * ninStopWhy:
  1072.  *    Assume the application program has stopped (i.e., a DLE was received
  1073.  *    from NINDY).  Ask NINDY for status information describing the
  1074.  *    reason for the halt.
  1075.  *
  1076.  *    Returns a non-zero value if the user program has exited, 0 otherwise.
  1077.  *    Also returns the following information, through passed pointers:
  1078.  *           - why: an exit code if program the exited; otherwise the reason
  1079.  *            why the program halted (see stop.h for values).
  1080.  *        - contents of register ip (little-endian byte order)
  1081.  *        - contents of register sp (little-endian byte order)
  1082.  *        - contents of register fp (little-endian byte order)
  1083.  ******************************************************************************/
  1084. char
  1085. OninStopWhy( whyp, ipp, fpp, spp )
  1086.     char *whyp;    /* Return the 'why' code through this pointer    */
  1087.     char *ipp;    /* Return contents of register ip through this pointer    */
  1088.     char *fpp;    /* Return contents of register fp through this pointer    */
  1089.     char *spp;    /* Return contents of register sp through this pointer    */
  1090. {
  1091.     char buf[30];
  1092.     char stop_exit;
  1093.  
  1094.     strcpy( buf, "?" );
  1095.     send( buf, FALSE );
  1096.     hexbin( 1, buf, &stop_exit );
  1097.     hexbin( 1, buf+2, whyp );
  1098.     hexbin( 4, buf+4, ipp );
  1099.     hexbin( 4, buf+12, fpp );
  1100.     hexbin( 4, buf+20, spp );
  1101.     return stop_exit;
  1102. }
  1103.  
  1104. /******************************************************************************
  1105.  * ninStrGet:
  1106.  *    Read a '\0'-terminated string of data out of the 960 memory space.
  1107.  *
  1108.  ******************************************************************************/
  1109. static
  1110. OninStrGet( ninaddr, hostaddr )
  1111.      unsigned long ninaddr;    /* Address of string in NINDY memory space */
  1112.      char *hostaddr;        /* Address of the buffer to which string should
  1113.                  *    be copied.
  1114.                  */
  1115. {
  1116.     char buf[BUFSIZE];    /* String as 2 ASCII hex digits per byte */
  1117.     int numchars;        /* Length of string in bytes.        */
  1118.  
  1119.     sprintf( buf, "\"%x", ninaddr );
  1120.     send( buf, FALSE );
  1121.     numchars = strlen(buf)/2;
  1122.     hexbin( numchars, buf, hostaddr );
  1123.     hostaddr[numchars] = '\0';
  1124. }
  1125.  
  1126. /******************************************************************************
  1127.  * ninVersion:
  1128.  *    Ask NINDY for version information about itself.
  1129.  *    The information is sent as an ascii string in the form "x.xx,<arch>",
  1130.  *    where,
  1131.  *        x.xx    is the version number
  1132.  *        <arch>    is the processor architecture: "KA", "KB", "MC", "CA" *
  1133.  *
  1134.  ******************************************************************************/
  1135. int
  1136. OninVersion( p )
  1137.      char *p;        /* Where to place version string */
  1138. {
  1139.     char buf[BUFSIZE];
  1140.  
  1141.     strcpy( buf, "v" );
  1142.     send( buf, FALSE );
  1143.     strcpy( p, buf );
  1144.     return strlen( buf );
  1145. }
  1146.