Commit | Line | Data |
---|---|---|
c906108c SS |
1 | /* This file is part of GDB. |
2 | ||
3 | This program is free software; you can redistribute it and/or modify | |
4 | it under the terms of the GNU General Public License as published by | |
5 | the Free Software Foundation; either version 2 of the License, or | |
6 | (at your option) any later version. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU General Public License for more details. | |
12 | ||
13 | You should have received a copy of the GNU General Public License | |
14 | along with this program; if not, write to the Free Software | |
15 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
16 | ||
17 | /* This started out life as code shared between the nindy monitor and | |
18 | GDB. For various reasons, this is no longer true. Eventually, it | |
19 | probably should be merged into remote-nindy.c. */ | |
20 | ||
21 | /****************************************************************************** | |
22 | * | |
23 | * NINDY INTERFACE ROUTINES | |
24 | * | |
25 | * 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 | \f | |
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 | \f | |
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 | \f | |
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 |