home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 9 / FreshFishVol9-CD2.bin / bbs / gnu / gdb-4.14-src.lha / gdb-4.14 / gdb / nindy-share / Onindy.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-28  |  21.2 KB  |  744 lines

  1. /* This file is part of GDB.
  2.  
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2 of the License, or
  6.    (at your option) any later version.
  7.  
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.  
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  16.  
  17. /* This started out life as code shared between the nindy monitor and
  18.    GDB.  For various reasons, this is no longer true.  Eventually, it
  19.    probably should be merged into remote-nindy.c.  */
  20.  
  21. /******************************************************************************
  22.  *
  23.  *             NINDY INTERFACE ROUTINES
  24.  *
  25.  * This version of the NINDY interface routines supports NINDY versions
  26.  * 2.13 and older.  The older versions used a hex communication protocol,
  27.  * instead of the (faster) current binary protocol.   These routines have
  28.  * been renamed by prepending the letter 'O' to their names, to avoid
  29.  * conflict with the current version.  The old versions are kept only for
  30.  * backward compatibility, and well disappear in a future release.
  31.  *
  32.  **************************************************************************/
  33.  
  34. /* Having these in a separate file from nindy.c is really ugly, and should
  35.    be merged with nindy.c.  */
  36.  
  37. #include <stdio.h>
  38. #if 0
  39. #include <sys/ioctl.h>
  40. #include <sys/types.h>    /* Needed by file.h on Sys V */
  41. #include <sys/file.h>
  42. #include <signal.h>
  43. #include <sys/stat.h>
  44. #include <fcntl.h>    /* Needed on Sys V */
  45. #include "ttycntl.h"
  46. #endif
  47. #include "defs.h"
  48. #include "serial.h"
  49.  
  50. #include "block_io.h"
  51. #include "wait.h"
  52. #include "env.h"
  53.  
  54. /* Number of bytes that we send to nindy.  I believe this is defined by
  55.    the protocol (it does not agree with REGISTER_BYTES).  */
  56. #define OLD_NINDY_REGISTER_BYTES ((36*4) + (4*8))
  57.  
  58. extern int quiet;    /* 1 => stifle unnecessary messages */
  59.  
  60. /* tty connected to 960/NINDY board.  */
  61. extern serial_t nindy_serial;
  62.  
  63. static OninStrGet();
  64.  
  65.         /****************************
  66.          *                          *
  67.          *  MISCELLANEOUS UTILTIES  *
  68.          *                          *
  69.          ****************************/
  70.  
  71.  
  72. /******************************************************************************
  73.  * fromhex:
  74.  *    Convert a hex ascii digit h to a binary integer
  75.  ******************************************************************************/
  76. static
  77. int
  78. fromhex( h )
  79.     int h;
  80. {
  81.     if (h >= '0' && h <= '9'){
  82.         h -= '0';
  83.     } else if (h >= 'a' && h <= 'f'){
  84.         h -= 'a' - 10;
  85.     } else {
  86.         h = 0;
  87.     }
  88.     return (h & 0xff);
  89. }
  90.  
  91.  
  92. /******************************************************************************
  93.  * hexbin:
  94.  *    Convert a string of ASCII hex digits to a string of binary bytes.
  95.  ******************************************************************************/
  96. static
  97. hexbin( n, hexp, binp )
  98.     int n;        /* Number of bytes to convert (twice this many digits)*/
  99.     char *hexp;        /* Get hex from here        */
  100.     char *binp;        /* Put binary here        */
  101. {
  102.     while ( n-- ){
  103.         *binp++ = (fromhex(*hexp) << 4) | fromhex(*(hexp+1));
  104.         hexp += 2;
  105.     }
  106. }
  107.  
  108.  
  109. /******************************************************************************
  110.  * binhex:
  111.  *    Convert a string of binary bytes to a string of ASCII hex digits
  112.  ******************************************************************************/
  113. static
  114. binhex( n, binp, hexp )
  115.     int n;              /* Number of bytes to convert   */
  116.     char *binp;         /* Get binary from here         */
  117.     char *hexp;         /* Place hex here               */
  118. {
  119.     static char tohex[] = "0123456789abcdef";
  120.  
  121.         while ( n-- ){
  122.                 *hexp++ = tohex[ (*binp >> 4) & 0xf ];
  123.                 *hexp++ = tohex[ *binp & 0xf ];
  124.                 binp++;
  125.         }
  126. }
  127.  
  128. /******************************************************************************
  129.  * byte_order:
  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. byte_order( 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.  
  159. /******************************************************************************
  160.  * say:
  161.  *    This is a printf that takes at most two arguments (in addition to the
  162.  *    format string) and that outputs nothing if verbose output has been
  163.  *    suppressed.
  164.  ******************************************************************************/
  165. static
  166. say( fmt, arg1, arg2 )
  167.     char *fmt;
  168.     int arg1, arg2;
  169. {
  170.     if ( !quiet ){
  171.         printf( fmt, arg1, arg2 );
  172.         fflush( stdout );
  173.     }
  174. }
  175.  
  176.         /*****************************
  177.          *                           *
  178.          *  LOW-LEVEL COMMUNICATION  *
  179.          *                           *
  180.          *****************************/
  181.  
  182. /* Read a single character from the remote end.  */
  183.  
  184. static int
  185. readchar()
  186. {
  187.   /* FIXME: Do we really want to be reading without a timeout?  */
  188.   return SERIAL_READCHAR (nindy_serial, -1);
  189. }
  190.  
  191. /******************************************************************************
  192.  * getpkt:
  193.  *    Read a packet from a remote NINDY, with error checking, and return
  194.  *    it in the indicated buffer.
  195.  ******************************************************************************/
  196. static
  197. getpkt (buf)
  198.      char *buf;
  199. {
  200.     unsigned char recv;    /* Checksum received        */
  201.     unsigned char csum;    /* Checksum calculated        */
  202.     char *bp;        /* Poointer into the buffer    */
  203.     int c;
  204.  
  205.     while (1){
  206.         csum = 0;
  207.         bp = buf;
  208.         /* FIXME: check for error from readchar ().  */
  209.         while ( (c = readchar()) != '#' ){
  210.             *bp++ = c;
  211.             csum += c;
  212.         }
  213.         *bp = 0;
  214.  
  215.         /* FIXME: check for error from readchar ().  */
  216.         recv = fromhex(readchar()) << 4;
  217.         recv |= fromhex(readchar());
  218.         if ( csum == recv ){
  219.             break;
  220.         }
  221.     
  222.         fprintf(stderr,
  223.             "Bad checksum (recv=0x%02x; calc=0x%02x); retrying\r\n",
  224.                                 recv, csum );
  225.         SERIAL_WRITE (nindy_serial, "-", 1);
  226.     }
  227.  
  228.     SERIAL_WRITE (nindy_serial, "+", 1);
  229. }
  230.  
  231.  
  232. /******************************************************************************
  233.  * putpkt:
  234.  *    Checksum and send a gdb command to a remote NINDY, and wait for
  235.  *    positive acknowledgement.
  236.  *
  237.  ******************************************************************************/
  238. static
  239. putpkt( cmd )
  240.     char *cmd;    /* Command to be sent, without lead ^P (\020)
  241.          * or trailing checksum
  242.          */
  243. {
  244.     char ack;    /* Response received from NINDY        */
  245.     char checksum[4];
  246.     char *p;
  247.     unsigned int s;
  248.     char resend;
  249.  
  250.     for ( s='\020', p=cmd; *p; p++ ){
  251.         s += *p;
  252.     }
  253.     sprintf( checksum, "#%02x",  s & 0xff );
  254.  
  255.     /* Send checksummed message over and over until we get a positive ack
  256.      */
  257.     resend = 1;
  258.     do {
  259.         if ( resend ) {
  260.           SERIAL_WRITE ( nindy_serial, "\020", 1 );
  261.           SERIAL_WRITE( nindy_serial, cmd, strlen(cmd) );
  262.           SERIAL_WRITE( nindy_serial, checksum, strlen(checksum) );
  263.         }
  264.         /* FIXME: do we really want to be reading without timeout?  */
  265.         ack = SERIAL_READCHAR (nindy_serial, -1);
  266.         if (ack < 0)
  267.           {
  268.             fprintf (stderr, "error reading from serial port\n");
  269.           }
  270.         if ( ack == '-' ){
  271.             fprintf( stderr, "Remote NAK, resending\r\n" );
  272.             resend = 1;
  273.         } else if ( ack != '+' ){
  274.             fprintf( stderr, "Bad ACK, ignored: <%c>\r\n", ack );
  275.             resend = 0;
  276.         }
  277.     } while ( ack != '+' );
  278. }
  279.  
  280.  
  281.  
  282. /******************************************************************************
  283.  * send:
  284.  *    Send a message to a remote NINDY and return the reply in the same
  285.  *    buffer (clobbers the input message).  Check for error responses
  286.  *    as indicated by the second argument.
  287.  *
  288.  ******************************************************************************/
  289. static
  290. send( buf, ack_required )
  291.     char *buf;        /* Message to be sent to NINDY; replaced by
  292.              *    NINDY's response.
  293.              */
  294.     int ack_required;    /* 1 means NINDY's response MUST be either "X00" (no
  295.              *    error) or an error code "Xnn".
  296.              * 0 means the it's OK as long as it doesn't
  297.              *    begin with "Xnn".
  298.              */
  299. {
  300.     int errnum;
  301.     static char *errmsg[] = {
  302.         "",                        /* X00 */
  303.         "Buffer overflow",                /* X01 */
  304.         "Unknown command",                /* X02 */
  305.         "Wrong amount of data to load register(s)",    /* X03 */
  306.         "Missing command argument(s)",            /* X04 */
  307.         "Odd number of digits sent to load memory",    /* X05 */
  308.         "Unknown register name",            /* X06 */
  309.         "No such memory segment",            /* X07 */
  310.         "No breakpoint available",            /* X08 */
  311.         "Can't set requested baud rate",        /* X09 */
  312.     };
  313. #    define NUMERRS    ( sizeof(errmsg) / sizeof(errmsg[0]) )
  314.  
  315.     static char err0[] = "NINDY failed to acknowledge command: <%s>\r\n";
  316.     static char err1[] = "Unknown error response from NINDY: <%s>\r\n";
  317.     static char err2[] = "Error response %s from NINDY: %s\r\n";
  318.  
  319.     putpkt (buf);
  320.     getpkt (buf);
  321.  
  322.     if ( buf[0] != 'X' ){
  323.         if ( ack_required ){
  324.             fprintf( stderr, err0, buf );
  325.             abort();
  326.         }
  327.  
  328.     } else if ( strcmp(buf,"X00") ){
  329.         sscanf( &buf[1], "%x", &errnum );
  330.         if ( errnum > NUMERRS ){
  331.             fprintf( stderr, err1, buf );
  332.         } else{
  333.             fprintf( stderr, err2, buf, errmsg[errnum] );
  334.         }
  335.         abort();
  336.     }
  337. }
  338.  
  339.         /**********************************
  340.          *                  *
  341.          *   NINDY INTERFACE ROUTINES      *
  342.          *                                  *
  343.          * ninConnect *MUST* be the first *
  344.          * one of these routines called.  *
  345.          **********************************/
  346.  
  347. /******************************************************************************
  348.  * ninBptDel:
  349.  *    Ask NINDY to delete the specified type of *hardware* breakpoint at
  350.  *    the specified address.  If the 'addr' is -1, all breakpoints of
  351.  *    the specified type are deleted.
  352.  ******************************************************************************/
  353. OninBptDel( addr, data )
  354.     long addr;    /* Address in 960 memory    */
  355.     int data;    /* '1' => data bkpt, '0' => instruction breakpoint */
  356. {
  357.     char buf[100];
  358.  
  359.     if ( addr == -1 ){
  360.         sprintf( buf, "b%c", data ? '1' : '0' );
  361.     } else {
  362.         sprintf( buf, "b%c%x", data ? '1' : '0', addr );
  363.     }
  364.     return send( buf, 0 );
  365. }
  366.  
  367.  
  368. /******************************************************************************
  369.  * ninBptSet:
  370.  *    Ask NINDY to set the specified type of *hardware* breakpoint at
  371.  *    the specified address.
  372.  ******************************************************************************/
  373. OninBptSet( addr, data )
  374.     long addr;    /* Address in 960 memory    */
  375.     int data;    /* '1' => data bkpt, '0' => instruction breakpoint */
  376. {
  377.     char buf[100];
  378.  
  379.     sprintf( buf, "B%c%x", data ? '1' : '0', addr );
  380.     return send( buf, 0 );
  381. }
  382.  
  383. /******************************************************************************
  384.  * ninGdbExit:
  385.  *    Ask NINDY to leave GDB mode and print a NINDY prompt.
  386.  *    Since it'll no longer be in GDB mode, don't wait for a response.
  387.  ******************************************************************************/
  388. OninGdbExit()
  389. {
  390.         putpkt( "E" );
  391. }
  392.  
  393. /******************************************************************************
  394.  * ninGo:
  395.  *    Ask NINDY to start or continue execution of an application program
  396.  *    in it's memory at the current ip.
  397.  ******************************************************************************/
  398. OninGo( step_flag )
  399.     int step_flag;    /* 1 => run in single-step mode */
  400. {
  401.     putpkt( step_flag ? "s" : "c" );
  402. }
  403.  
  404.  
  405. /******************************************************************************
  406.  * ninMemGet:
  407.  *    Read a string of bytes from NINDY's address space (960 memory).
  408.  ******************************************************************************/
  409. OninMemGet(ninaddr, hostaddr, len)
  410.      long ninaddr;    /* Source address, in the 960 memory space    */
  411.      char *hostaddr;    /* Destination address, in our memory space    */
  412.      int len;        /* Number of bytes to read            */
  413. {
  414.   /* How much do we send at a time?  */
  415. #define OLD_NINDY_MEMBYTES 1024
  416.     /* Buffer: hex in, binary out        */
  417.     char buf[2*OLD_NINDY_MEMBYTES+20];
  418.  
  419.     int cnt;        /* Number of bytes in next transfer    */
  420.  
  421.     for ( ; len > 0; len -= OLD_NINDY_MEMBYTES ){
  422.         cnt = len > OLD_NINDY_MEMBYTES ? OLD_NINDY_MEMBYTES : len;
  423.  
  424.         sprintf( buf, "m%x,%x", ninaddr, cnt );
  425.         send( buf, 0 );
  426.         hexbin( cnt, buf, hostaddr );
  427.  
  428.         ninaddr += cnt;
  429.         hostaddr += cnt;
  430.     }
  431. }
  432.  
  433.  
  434. /******************************************************************************
  435.  * ninMemPut:
  436.  *    Write a string of bytes into NINDY's address space (960 memory).
  437.  ******************************************************************************/
  438. OninMemPut( destaddr, srcaddr, len )
  439.      long destaddr;    /* Destination address, in NINDY memory space    */
  440.      char *srcaddr;    /* Source address, in our memory space        */
  441.      int len;        /* Number of bytes to write            */
  442. {
  443.     char buf[2*OLD_NINDY_MEMBYTES+20];    /* Buffer: binary in, hex out        */
  444.     char *p;        /* Pointer into buffer            */
  445.     int cnt;        /* Number of bytes in next transfer    */
  446.  
  447.     for ( ; len > 0; len -= OLD_NINDY_MEMBYTES ){
  448.         cnt = len > OLD_NINDY_MEMBYTES ? OLD_NINDY_MEMBYTES : len;
  449.  
  450.         sprintf( buf, "M%x,", destaddr );
  451.         p = buf + strlen(buf);
  452.         binhex( cnt, srcaddr, p );
  453.         *(p+(2*cnt)) = '\0';
  454.         send( buf, 1 );
  455.  
  456.         srcaddr += cnt;
  457.         destaddr += cnt;
  458.     }
  459. }
  460.  
  461. /******************************************************************************
  462.  * ninRegGet:
  463.  *    Retrieve the contents of a 960 register, and return them as a long
  464.  *    in host byte order.
  465.  *
  466.  *    THIS ROUTINE CAN ONLY BE USED TO READ THE LOCAL, GLOBAL, AND
  467.  *    ip/ac/pc/tc REGISTERS.
  468.  *
  469.  ******************************************************************************/
  470. long
  471. OninRegGet( regname )
  472.     char *regname;    /* Register name recognized by NINDY, subject to the
  473.              * above limitations.
  474.              */
  475. {
  476.     char buf[200];
  477.     long val;
  478.  
  479.     sprintf( buf, "u%s", regname );
  480.     send( buf, 0 );
  481.     hexbin( 4, buf, (char *)&val );
  482.     return byte_order(val);
  483. }
  484.  
  485. /******************************************************************************
  486.  * ninRegPut:
  487.  *    Set the contents of a 960 register.
  488.  *
  489.  *    THIS ROUTINE CAN ONLY BE USED TO SET THE LOCAL, GLOBAL, AND
  490.  *    ip/ac/pc/tc REGISTERS.
  491.  *
  492.  ******************************************************************************/
  493. OninRegPut( regname, val )
  494.     char *regname;    /* Register name recognized by NINDY, subject to the
  495.              * above limitations.
  496.              */
  497.     long val;        /* New contents of register, in host byte-order    */
  498. {
  499.     char buf[200];
  500.  
  501.     sprintf( buf, "U%s,%08x", regname, byte_order(val) );
  502.     send( buf, 1 );
  503. }
  504.  
  505. /******************************************************************************
  506.  * ninRegsGet:
  507.  *    Get a dump of the contents of the entire 960 register set.  The
  508.  *    individual registers appear in the dump in the following order:
  509.  *
  510.  *        pfp  sp   rip  r3   r4   r5   r6   r7 
  511.  *        r8   r9   r10  r11  r12  r13  r14  r15 
  512.  *        g0   g1   g2   g3   g4   g5   g6   g7 
  513.  *        g8   g9   g10  g11  g12  g13  g14  fp 
  514.  *        pc   ac   ip   tc   fp0  fp1  fp2  fp3
  515.  *
  516.  *    Each individual register comprises exactly 4 bytes, except for
  517.  *    fp0-fp3, which are 8 bytes.
  518.  *
  519.  * WARNING:
  520.  *    Each register value is in 960 (little-endian) byte order.
  521.  *
  522.  ******************************************************************************/
  523. OninRegsGet( regp )
  524.     char *regp;        /* Where to place the register dump */
  525. {
  526.     char buf[(2*OLD_NINDY_REGISTER_BYTES)+10];   /* Registers in ASCII hex */
  527.  
  528.     strcpy( buf, "r" );
  529.     send( buf, 0 );
  530.     hexbin( OLD_NINDY_REGISTER_BYTES, buf, regp );
  531. }
  532.  
  533. /******************************************************************************
  534.  * ninRegsPut:
  535.  *    Initialize the entire 960 register set to a specified set of values.
  536.  *    The format of the register value data should be the same as that
  537.  *    returned by ninRegsGet.
  538.  *
  539.  * WARNING:
  540.  *    Each register value should be in 960 (little-endian) byte order.
  541.  *
  542.  ******************************************************************************/
  543. OninRegsPut( regp )
  544.     char *regp;        /* Pointer to desired values of registers */
  545. {
  546.     char buf[(2*OLD_NINDY_REGISTER_BYTES)+10];   /* Registers in ASCII hex */
  547.  
  548.     buf[0] = 'R';
  549.     binhex( OLD_NINDY_REGISTER_BYTES, regp, buf+1 );
  550.     buf[ (2*OLD_NINDY_REGISTER_BYTES)+1 ] = '\0';
  551.  
  552.     send( buf, 1 );
  553. }
  554.  
  555.  
  556. /******************************************************************************
  557.  * ninReset:
  558.  *      Ask NINDY to perform a soft reset; wait for the reset to complete.
  559.  ******************************************************************************/
  560. OninReset()
  561. {
  562.  
  563.     putpkt( "X" );
  564.     /* FIXME: check for error from readchar ().  */
  565.     while ( readchar() != '+' ){
  566.         ;
  567.     }
  568. }
  569.  
  570.  
  571. /******************************************************************************
  572.  * ninSrq:
  573.  *    Assume NINDY has stopped execution of the 960 application program in
  574.  *    order to process a host service request (srq).  Ask NINDY for the
  575.  *    srq arguments, perform the requested service, and send an "srq
  576.  *    complete" message so NINDY will return control to the application.
  577.  *
  578.  ******************************************************************************/
  579. OninSrq()
  580. {
  581.   /* FIXME: Imposes arbitrary limits on lengths of pathnames and such.  */
  582.     char buf[BUFSIZE];
  583.     int retcode;
  584.     unsigned char srqnum;
  585.     char *p;
  586.     char *argp;
  587.     int nargs;
  588.     int arg[MAX_SRQ_ARGS];
  589.  
  590.  
  591.     /* Get srq number and arguments
  592.      */
  593.     strcpy( buf, "!" );
  594.     send( buf, 0 );
  595.     hexbin( 1, buf, (char *)&srqnum );
  596.  
  597.     /* Set up array of pointers the each of the individual
  598.      * comma-separated args
  599.      */
  600.     nargs=0;
  601.     argp = p = buf+2;
  602.         while ( 1 ){
  603.                 while ( *p != ',' && *p != '\0' ){
  604.                         p++;
  605.                 }
  606.                 sscanf( argp, "%x", &arg[nargs++] );
  607.                 if ( *p == '\0' || nargs == MAX_SRQ_ARGS ){
  608.                         break;
  609.                 }
  610.                 argp = ++p;
  611.         }
  612.  
  613.     /* Process Srq
  614.      */
  615.     switch( srqnum ){
  616.     case BS_CLOSE:
  617.         /* args: file descriptor */
  618.         if ( arg[0] > 2 ){
  619.             retcode = close( arg[0] );
  620.         } else {
  621.             retcode = 0;
  622.         }
  623.         break;
  624.     case BS_CREAT:
  625.         /* args: filename, mode */
  626.         OninStrGet( arg[0], buf );
  627.         retcode = creat(buf,arg[1]);
  628.         break;
  629.     case BS_OPEN:
  630.         /* args: filename, flags, mode */
  631.         OninStrGet( arg[0], buf );
  632.         retcode = open(buf,arg[1],arg[2]);
  633.         break;
  634.     case BS_READ:
  635.         /* args: file descriptor, buffer, count */
  636.         retcode = read(arg[0],buf,arg[2]);
  637.         if ( retcode > 0 ){
  638.             OninMemPut( arg[1], buf, retcode );
  639.         }
  640.         break;
  641.     case BS_SEEK:
  642.         /* args: file descriptor, offset, whence */
  643.         retcode = lseek(arg[0],arg[1],arg[2]);
  644.         break;
  645.     case BS_WRITE:
  646.         /* args: file descriptor, buffer, count */
  647.         OninMemGet( arg[1], buf, arg[2] );
  648.         retcode = write(arg[0],buf,arg[2]);
  649.         break;
  650.     default:
  651.         retcode = -1;
  652.         break;
  653.     }
  654.  
  655.     /* Tell NINDY to continue
  656.      */
  657.     sprintf( buf, "e%x", retcode );
  658.     send( buf, 1 );
  659. }
  660.  
  661.  
  662. /******************************************************************************
  663.  * ninStopWhy:
  664.  *    Assume the application program has stopped (i.e., a DLE was received
  665.  *    from NINDY).  Ask NINDY for status information describing the
  666.  *    reason for the halt.
  667.  *
  668.  *    Returns a non-zero value if the user program has exited, 0 otherwise.
  669.  *    Also returns the following information, through passed pointers:
  670.  *           - why: an exit code if program the exited; otherwise the reason
  671.  *            why the program halted (see stop.h for values).
  672.  *        - contents of register ip (little-endian byte order)
  673.  *        - contents of register sp (little-endian byte order)
  674.  *        - contents of register fp (little-endian byte order)
  675.  ******************************************************************************/
  676. char
  677. OninStopWhy( whyp, ipp, fpp, spp )
  678.     char *whyp;    /* Return the 'why' code through this pointer    */
  679.     char *ipp;    /* Return contents of register ip through this pointer    */
  680.     char *fpp;    /* Return contents of register fp through this pointer    */
  681.     char *spp;    /* Return contents of register sp through this pointer    */
  682. {
  683.     char buf[30];
  684.     char stop_exit;
  685.  
  686.     strcpy( buf, "?" );
  687.     send( buf, 0 );
  688.     hexbin( 1, buf, &stop_exit );
  689.     hexbin( 1, buf+2, whyp );
  690.     hexbin( 4, buf+4, ipp );
  691.     hexbin( 4, buf+12, fpp );
  692.     hexbin( 4, buf+20, spp );
  693.     return stop_exit;
  694. }
  695.  
  696. /******************************************************************************
  697.  * ninStrGet:
  698.  *    Read a '\0'-terminated string of data out of the 960 memory space.
  699.  *
  700.  ******************************************************************************/
  701. static
  702. OninStrGet( ninaddr, hostaddr )
  703.      unsigned long ninaddr;    /* Address of string in NINDY memory space */
  704.      char *hostaddr;        /* Address of the buffer to which string should
  705.                  *    be copied.
  706.                  */
  707. {
  708.   /* FIXME: seems to be an arbitrary limit on the length of the string.  */
  709.     char buf[BUFSIZE];    /* String as 2 ASCII hex digits per byte */
  710.     int numchars;        /* Length of string in bytes.        */
  711.  
  712.     sprintf( buf, "\"%x", ninaddr );
  713.     send( buf, 0 );
  714.     numchars = strlen(buf)/2;
  715.     hexbin( numchars, buf, hostaddr );
  716.     hostaddr[numchars] = '\0';
  717. }
  718.  
  719. #if 0
  720. /* never used.  */
  721.  
  722. /******************************************************************************
  723.  * ninVersion:
  724.  *    Ask NINDY for version information about itself.
  725.  *    The information is sent as an ascii string in the form "x.xx,<arch>",
  726.  *    where,
  727.  *        x.xx    is the version number
  728.  *        <arch>    is the processor architecture: "KA", "KB", "MC", "CA" *
  729.  *
  730.  ******************************************************************************/
  731. int
  732. OninVersion( p )
  733.      char *p;        /* Where to place version string */
  734. {
  735.   /* FIXME: this is an arbitrary limit on the length of version string.  */
  736.     char buf[BUFSIZE];
  737.  
  738.     strcpy( buf, "v" );
  739.     send( buf, 0 );
  740.     strcpy( p, buf );
  741.     return strlen( buf );
  742. }
  743. #endif
  744.