]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/remote-adapt.c
Initial creation of sourceware repository
[thirdparty/binutils-gdb.git] / gdb / remote-adapt.c
1 /* Remote debugging interface for AMD 290*0 Adapt Monitor Version 2.1d18.
2 Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
3 Contributed by David Wood at New York University (wood@lab.ultra.nyu.edu).
4 Adapted from work done at Cygnus Support in remote-eb.c.
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21
22 /* This is like remote.c but is for an esoteric situation--
23 having a 29k board attached to an Adapt inline monitor.
24 The monitor is connected via serial line to a unix machine
25 running gdb.
26
27 3/91 - developed on Sun3 OS 4.1, by David Wood
28 o - I can't get binary coff to load.
29 o - I can't get 19200 baud rate to work.
30 7/91 o - Freeze mode tracing can be done on a 29050. */
31
32
33
34 #include "defs.h"
35 #include "gdb_string.h"
36 #include "inferior.h"
37 #include "wait.h"
38 #include "value.h"
39 #include <ctype.h>
40 #include <fcntl.h>
41 #include <signal.h>
42 #include <errno.h>
43 #include "terminal.h"
44 #include "target.h"
45 #include "gdbcore.h"
46
47 /* This processor is getting rusty but I am trying to keep it
48 up to date at least with data structure changes.
49 Activate this block to compile just this file.
50 */
51 #define COMPILE_CHECK 0
52 #if COMPILE_CHECK
53 #define Q_REGNUM 0
54 #define VAB_REGNUM 0
55 #define CPS_REGNUM 0
56 #define IPA_REGNUM 0
57 #define IPB_REGNUM 0
58 #define GR1_REGNUM 0
59 #define LR0_REGNUM 0
60 #define IPC_REGNUM 0
61 #define CR_REGNUM 0
62 #define BP_REGNUM 0
63 #define FC_REGNUM 0
64 #define INTE_REGNUM 0
65 #define EXO_REGNUM 0
66 #define GR96_REGNUM 0
67 #define NPC_REGNUM
68 #define FPE_REGNUM 0
69 #define PC2_REGNUM 0
70 #define FPS_REGNUM 0
71 #define ALU_REGNUM 0
72 #define LRU_REGNUM 0
73 #define TERMINAL int
74 #define RAW 1
75 #define ANYP 1
76 extern int a29k_freeze_mode ;
77 extern int processor_type ;
78 extern char * processor_name ;
79 #endif
80
81 /* External data declarations */
82 extern int stop_soon_quietly; /* for wait_for_inferior */
83
84 /* Forward data declarations */
85 extern struct target_ops adapt_ops; /* Forward declaration */
86
87 /* Forward function declarations */
88 static void adapt_fetch_registers ();
89 static void adapt_store_registers ();
90 static void adapt_close ();
91 static int adapt_clear_breakpoints();
92
93 #define FREEZE_MODE (read_register(CPS_REGNUM) && 0x400)
94 #define USE_SHADOW_PC ((processor_type == a29k_freeze_mode) && FREEZE_MODE)
95
96 /* Can't seem to get binary coff working */
97 #define ASCII_COFF /* Adapt will be downloaded with ascii coff */
98
99 /* FIXME: Replace with `set remotedebug'. */
100 #define LOG_FILE "adapt.log"
101 #if defined (LOG_FILE)
102 FILE *log_file=NULL;
103 #endif
104
105 static int timeout = 5;
106 static char *dev_name;
107
108 /* Descriptor for I/O to remote machine. Initialize it to -1 so that
109 adapt_open knows that we don't have a file open when the program
110 starts. */
111 int adapt_desc = -1;
112
113 /* stream which is fdopen'd from adapt_desc. Only valid when
114 adapt_desc != -1. */
115 FILE *adapt_stream;
116
117 #define ON 1
118 #define OFF 0
119 static void
120 rawmode(desc, turnon)
121 int desc;
122 int turnon;
123 {
124
125 TERMINAL sg;
126
127 if (desc < 0)
128 return;
129
130 ioctl (desc, TIOCGETP, &sg);
131
132 if (turnon) {
133 #ifdef HAVE_TERMIO
134 sg.c_lflag &= ~(ICANON);
135 #else
136 sg.sg_flags |= RAW;
137 #endif
138 } else {
139 #ifdef HAVE_TERMIO
140 sg.c_lflag |= ICANON;
141 #else
142 sg.sg_flags &= ~(RAW);
143 #endif
144 }
145 ioctl (desc, TIOCSETP, &sg);
146 }
147
148 /* Suck up all the input from the adapt */
149 slurp_input()
150 {
151 char buf[8];
152
153 #ifdef HAVE_TERMIO
154 /* termio does the timeout for us. */
155 while (read (adapt_desc, buf, 8) > 0);
156 #else
157 alarm (timeout);
158 while (read (adapt_desc, buf, 8) > 0);
159 alarm (0);
160 #endif
161 }
162
163 /* Read a character from the remote system, doing all the fancy
164 timeout stuff. */
165 static int
166 readchar ()
167 {
168 char buf;
169
170 buf = '\0';
171 #ifdef HAVE_TERMIO
172 /* termio does the timeout for us. */
173 read (adapt_desc, &buf, 1);
174 #else
175 alarm (timeout);
176 if (read (adapt_desc, &buf, 1) < 0)
177 {
178 if (errno == EINTR)
179 error ("Timeout reading from remote system.");
180 else
181 perror_with_name ("remote");
182 }
183 alarm (0);
184 #endif
185
186 if (buf == '\0')
187 error ("Timeout reading from remote system.");
188 #if defined (LOG_FILE)
189 putc (buf & 0x7f, log_file);
190 #endif
191 return buf & 0x7f;
192 }
193
194 /* Keep discarding input from the remote system, until STRING is found.
195 Let the user break out immediately. */
196 static void
197 expect (string)
198 char *string;
199 {
200 char *p = string;
201
202 fflush(adapt_stream);
203 immediate_quit = 1;
204 while (1)
205 {
206 if (readchar() == *p)
207 {
208 p++;
209 if (*p == '\0')
210 {
211 immediate_quit = 0;
212 return;
213 }
214 }
215 else
216 p = string;
217 }
218 }
219
220 /* Keep discarding input until we see the adapt prompt.
221
222 The convention for dealing with the prompt is that you
223 o give your command
224 o *then* wait for the prompt.
225
226 Thus the last thing that a procedure does with the serial line
227 will be an expect_prompt(). Exception: adapt_resume does not
228 wait for the prompt, because the terminal is being handed over
229 to the inferior. However, the next thing which happens after that
230 is a adapt_wait which does wait for the prompt.
231 Note that this includes abnormal exit, e.g. error(). This is
232 necessary to prevent getting into states from which we can't
233 recover. */
234 static void
235 expect_prompt ()
236 {
237 #if defined (LOG_FILE)
238 /* This is a convenient place to do this. The idea is to do it often
239 enough that we never lose much data if we terminate abnormally. */
240 fflush (log_file);
241 #endif
242 fflush(adapt_stream);
243 expect ("\n# ");
244 }
245
246 /* Get a hex digit from the remote system & return its value.
247 If ignore_space is nonzero, ignore spaces (not newline, tab, etc). */
248 static int
249 get_hex_digit (ignore_space)
250 int ignore_space;
251 {
252 int ch;
253 while (1)
254 {
255 ch = readchar ();
256 if (ch >= '0' && ch <= '9')
257 return ch - '0';
258 else if (ch >= 'A' && ch <= 'F')
259 return ch - 'A' + 10;
260 else if (ch >= 'a' && ch <= 'f')
261 return ch - 'a' + 10;
262 else if (ch == ' ' && ignore_space)
263 ;
264 else
265 {
266 expect_prompt ();
267 error ("Invalid hex digit from remote system.");
268 }
269 }
270 }
271
272 /* Get a byte from adapt_desc and put it in *BYT. Accept any number
273 leading spaces. */
274 static void
275 get_hex_byte (byt)
276 char *byt;
277 {
278 int val;
279
280 val = get_hex_digit (1) << 4;
281 val |= get_hex_digit (0);
282 *byt = val;
283 }
284
285 /* Read a 32-bit hex word from the adapt, preceded by a space */
286 static long
287 get_hex_word()
288 {
289 long val;
290 int j;
291
292 val = 0;
293 for (j = 0; j < 8; j++)
294 val = (val << 4) + get_hex_digit (j == 0);
295 return val;
296 }
297 /* Get N 32-bit hex words from remote, each preceded by a space
298 and put them in registers starting at REGNO. */
299 static void
300 get_hex_regs (n, regno)
301 int n;
302 int regno;
303 {
304 long val;
305 while (n--) {
306 val = get_hex_word();
307 supply_register(regno++,(char *) &val);
308 }
309 }
310 /* Called when SIGALRM signal sent due to alarm() timeout. */
311 #ifndef HAVE_TERMIO
312
313 #ifndef __STDC__
314 # ifndef volatile
315 # define volatile /**/
316 # endif
317 #endif
318 volatile int n_alarms;
319
320 void
321 adapt_timer ()
322 {
323 #if 0
324 if (kiodebug)
325 printf ("adapt_timer called\n");
326 #endif
327 n_alarms++;
328 }
329 #endif
330
331 /* malloc'd name of the program on the remote system. */
332 static char *prog_name = NULL;
333
334 /* Number of SIGTRAPs we need to simulate. That is, the next
335 NEED_ARTIFICIAL_TRAP calls to adapt_wait should just return
336 SIGTRAP without actually waiting for anything. */
337
338 static int need_artificial_trap = 0;
339
340 void
341 adapt_kill(arg,from_tty)
342 char *arg;
343 int from_tty;
344 {
345 fprintf (adapt_stream, "K");
346 fprintf (adapt_stream, "\r");
347 expect_prompt ();
348 }
349 /*
350 * Download a file specified in 'args', to the adapt.
351 * FIXME: Assumes the file to download is a binary coff file.
352 */
353 static void
354 adapt_load(args,fromtty)
355 char *args;
356 int fromtty;
357 {
358 FILE *fp;
359 int n;
360 char buffer[1024];
361
362 if (!adapt_stream) {
363 printf_filtered("Adapt not open. Use 'target' command to open adapt\n");
364 return;
365 }
366
367 /* OK, now read in the file. Y=read, C=COFF, T=dTe port
368 0=start address. */
369
370 #ifdef ASCII_COFF /* Ascii coff */
371 fprintf (adapt_stream, "YA T,0\r");
372 fflush(adapt_stream); /* Just in case */
373 /* FIXME: should check args for only 1 argument */
374 sprintf(buffer,"cat %s | btoa > /tmp/#adapt-btoa",args);
375 system(buffer);
376 fp = fopen("/tmp/#adapt-btoa","r");
377 rawmode(adapt_desc,OFF);
378 while (n=fread(buffer,1,1024,fp)) {
379 do { n -= write(adapt_desc,buffer,n); } while (n>0);
380 if (n<0) { perror("writing ascii coff"); break; }
381 }
382 fclose(fp);
383 rawmode(adapt_desc,ON);
384 system("rm /tmp/#adapt-btoa");
385 #else /* Binary coff - can't get it to work .*/
386 fprintf (adapt_stream, "YC T,0\r");
387 fflush(adapt_stream); /* Just in case */
388 if (!(fp = fopen(args,"r"))) {
389 printf_filtered("Can't open %s\n",args);
390 return;
391 }
392 while (n=fread(buffer,1,512,fp)) {
393 do { n -= write(adapt_desc,buffer,n); } while (n>0);
394 if (n<0) { perror("writing ascii coff"); break; }
395 }
396 fclose(fp);
397 #endif
398 expect_prompt (); /* Skip garbage that comes out */
399 fprintf (adapt_stream, "\r");
400 expect_prompt ();
401 }
402
403 /* This is called not only when we first attach, but also when the
404 user types "run" after having attached. */
405 void
406 adapt_create_inferior (execfile, args, env)
407 char *execfile;
408 char *args;
409 char **env;
410 {
411 int entry_pt;
412
413 if (args && *args)
414 error ("Can't pass arguments to remote adapt process.");
415
416 if (execfile == 0 || exec_bfd == 0)
417 error ("No executable file specified");
418
419 entry_pt = (int) bfd_get_start_address (exec_bfd);
420
421 if (adapt_stream) {
422 adapt_kill(NULL,NULL);
423 adapt_clear_breakpoints();
424 init_wait_for_inferior ();
425 /* Clear the input because what the adapt sends back is different
426 * depending on whether it was running or not.
427 */
428 slurp_input(); /* After this there should be a prompt */
429 fprintf(adapt_stream,"\r");
430 expect_prompt();
431 printf_filtered("Do you want to download '%s' (y/n)? [y] : ",prog_name);
432 {
433 char buffer[10];
434 gets(buffer);
435 if (*buffer != 'n') {
436 adapt_load(prog_name,0);
437 }
438 }
439
440 #ifdef NOTDEF
441 /* Set the PC and wait for a go/cont */
442 fprintf (adapt_stream, "G %x,N\r",entry_pt);
443 printf_filtered("Now use the 'continue' command to start.\n");
444 expect_prompt ();
445 #else
446 insert_breakpoints (); /* Needed to get correct instruction in cache */
447 proceed(entry_pt, TARGET_SIGNAL_DEFAULT, 0);
448 #endif
449
450 } else {
451 printf_filtered("Adapt not open yet.\n");
452 }
453 }
454
455 /* Translate baud rates from integers to damn B_codes. Unix should
456 have outgrown this crap years ago, but even POSIX wouldn't buck it. */
457
458 #ifndef B19200
459 #define B19200 EXTA
460 #endif
461 #ifndef B38400
462 #define B38400 EXTB
463 #endif
464
465 static struct {int rate, damn_b;} baudtab[] = {
466 {0, B0},
467 {50, B50},
468 {75, B75},
469 {110, B110},
470 {134, B134},
471 {150, B150},
472 {200, B200},
473 {300, B300},
474 {600, B600},
475 {1200, B1200},
476 {1800, B1800},
477 {2400, B2400},
478 {4800, B4800},
479 {9600, B9600},
480 {19200, B19200},
481 {38400, B38400},
482 {-1, -1},
483 };
484
485 static int damn_b (rate)
486 int rate;
487 {
488 int i;
489
490 for (i = 0; baudtab[i].rate != -1; i++)
491 if (rate == baudtab[i].rate) return baudtab[i].damn_b;
492 return B38400; /* Random */
493 }
494
495
496 /* Open a connection to a remote debugger.
497 NAME is the filename used for communication, then a space,
498 then the baud rate.
499 */
500
501 static int baudrate = 9600;
502 static void
503 adapt_open (name, from_tty)
504 char *name;
505 int from_tty;
506 {
507 TERMINAL sg;
508 unsigned int prl;
509 char *p;
510
511 /* Find the first whitespace character, it separates dev_name from
512 prog_name. */
513 if (name == 0)
514 goto erroid;
515
516 for (p = name;
517 *p != '\0' && !isspace (*p); p++)
518 ;
519 if (*p == '\0')
520 erroid:
521 error ("\
522 Please include the name of the device for the serial port,\n\
523 the baud rate, and the name of the program to run on the remote system.");
524 dev_name = (char*)xmalloc(p - name + 1);
525 strncpy (dev_name, name, p - name);
526 dev_name[p - name] = '\0';
527
528 /* Skip over the whitespace after dev_name */
529 for (; isspace (*p); p++)
530 /*EMPTY*/;
531
532 if (1 != sscanf (p, "%d ", &baudrate))
533 goto erroid;
534
535 /* Skip the number and then the spaces */
536 for (; isdigit (*p); p++)
537 /*EMPTY*/;
538 for (; isspace (*p); p++)
539 /*EMPTY*/;
540
541 if (prog_name != NULL)
542 free (prog_name);
543 prog_name = savestring (p, strlen (p));
544
545 adapt_close (0);
546
547 adapt_desc = open (dev_name, O_RDWR);
548 if (adapt_desc < 0)
549 perror_with_name (dev_name);
550 ioctl (adapt_desc, TIOCGETP, &sg);
551 #if ! defined(COMPILE_CHECK)
552 #ifdef HAVE_TERMIO
553 sg.c_cc[VMIN] = 0; /* read with timeout. */
554 sg.c_cc[VTIME] = timeout * 10;
555 sg.c_lflag &= ~(ICANON | ECHO);
556 sg.c_cflag = (sg.c_cflag & ~CBAUD) | damn_b (baudrate);
557 #else
558 sg.sg_ispeed = damn_b (baudrate);
559 sg.sg_ospeed = damn_b (baudrate);
560 sg.sg_flags |= RAW | ANYP;
561 sg.sg_flags &= ~ECHO;
562 #endif
563
564 ioctl (adapt_desc, TIOCSETP, &sg);
565 adapt_stream = fdopen (adapt_desc, "r+");
566 #endif /* compile_check */
567 push_target (&adapt_ops);
568
569 #ifndef HAVE_TERMIO
570 #ifndef NO_SIGINTERRUPT
571 /* Cause SIGALRM's to make reads fail with EINTR instead of resuming
572 the read. */
573 if (siginterrupt (SIGALRM, 1) != 0)
574 perror ("adapt_open: error in siginterrupt");
575 #endif
576
577 /* Set up read timeout timer. */
578 if ((void (*)) signal (SIGALRM, adapt_timer) == (void (*)) -1)
579 perror ("adapt_open: error in signal");
580 #endif
581
582 #if defined (LOG_FILE)
583 log_file = fopen (LOG_FILE, "w");
584 if (log_file == NULL)
585 perror_with_name (LOG_FILE);
586 #endif
587
588 /* Put this port into NORMAL mode, send the 'normal' character */
589 write(adapt_desc, "\ 1", 1); /* Control A */
590 write(adapt_desc, "\r", 1);
591 expect_prompt ();
592
593 /* Hello? Are you there? */
594 write (adapt_desc, "\r", 1);
595
596 expect_prompt ();
597
598 /* Clear any break points */
599 adapt_clear_breakpoints();
600
601 /* Print out some stuff, letting the user now what's going on */
602 printf_filtered("Connected to an Adapt via %s.\n", dev_name);
603 /* FIXME: can this restriction be removed? */
604 printf_filtered("Remote debugging using virtual addresses works only\n");
605 printf_filtered("\twhen virtual addresses map 1:1 to physical addresses.\n");
606 if (processor_type != a29k_freeze_mode) {
607 fprintf_filtered(gdb_stderr,
608 "Freeze-mode debugging not available, and can only be done on an A29050.\n");
609 }
610 }
611
612 /* Close out all files and local state before this target loses control. */
613
614 static void
615 adapt_close (quitting)
616 int quitting;
617 {
618
619 /* Clear any break points */
620 adapt_clear_breakpoints();
621
622 /* Put this port back into REMOTE mode */
623 if (adapt_stream) {
624 fflush(adapt_stream);
625 sleep(1); /* Let any output make it all the way back */
626 write(adapt_desc, "R\r", 2);
627 }
628
629 /* Due to a bug in Unix, fclose closes not only the stdio stream,
630 but also the file descriptor. So we don't actually close
631 adapt_desc. */
632 if (adapt_stream)
633 fclose (adapt_stream); /* This also closes adapt_desc */
634 if (adapt_desc >= 0)
635 /* close (adapt_desc); */
636
637 /* Do not try to close adapt_desc again, later in the program. */
638 adapt_stream = NULL;
639 adapt_desc = -1;
640
641 #if defined (LOG_FILE)
642 if (log_file) {
643 if (ferror (log_file))
644 printf_filtered ("Error writing log file.\n");
645 if (fclose (log_file) != 0)
646 printf_filtered ("Error closing log file.\n");
647 log_file = NULL;
648 }
649 #endif
650 }
651
652 /* Attach to the target that is already loaded and possibly running */
653 static void
654 adapt_attach (args, from_tty)
655 char *args;
656 int from_tty;
657 {
658
659 if (from_tty)
660 printf_filtered ("Attaching to remote program %s.\n", prog_name);
661
662 /* Send the adapt a kill. It is ok if it is not already running */
663 fprintf(adapt_stream, "K\r"); fflush(adapt_stream);
664 expect_prompt(); /* Slurp the echo */
665 }
666
667
668 /* Terminate the open connection to the remote debugger.
669 Use this when you want to detach and do something else
670 with your gdb. */
671 void
672 adapt_detach (args,from_tty)
673 char *args;
674 int from_tty;
675 {
676
677 if (adapt_stream) { /* Send it on its way (tell it to continue) */
678 adapt_clear_breakpoints();
679 fprintf(adapt_stream,"G\r");
680 }
681
682 pop_target(); /* calls adapt_close to do the real work */
683 if (from_tty)
684 printf_filtered ("Ending remote %s debugging\n", target_shortname);
685 }
686
687 /* Tell the remote machine to resume. */
688
689 void
690 adapt_resume (pid, step, sig)
691 int pid, step;
692 enum target_signal sig;
693 {
694 if (step)
695 {
696 write (adapt_desc, "t 1,s\r", 6);
697 /* Wait for the echo. */
698 expect ("t 1,s\r\n");
699 /* Then comes a line containing the instruction we stepped to. */
700 expect ("@");
701 /* Then we get the prompt. */
702 expect_prompt ();
703
704 /* Force the next adapt_wait to return a trap. Not doing anything
705 about I/O from the target means that the user has to type
706 "continue" to see any. FIXME, this should be fixed. */
707 need_artificial_trap = 1;
708 }
709 else
710 {
711 write (adapt_desc, "G\r", 2);
712 /* Swallow the echo. */
713 expect_prompt();
714 }
715 }
716
717 /* Wait until the remote machine stops, then return,
718 storing status in STATUS just as `wait' would. */
719
720 int
721 adapt_wait (status)
722 struct target_waitstatus *status;
723 {
724 /* Strings to look for. '?' means match any single character.
725 Note that with the algorithm we use, the initial character
726 of the string cannot recur in the string, or we will not
727 find some cases of the string in the input. */
728
729 static char bpt[] = "@";
730 /* It would be tempting to look for "\n[__exit + 0x8]\n"
731 but that requires loading symbols with "yc i" and even if
732 we did do that we don't know that the file has symbols. */
733 static char exitmsg[] = "@????????I JMPTI GR121,LR0";
734 char *bp = bpt;
735 char *ep = exitmsg;
736
737 /* Large enough for either sizeof (bpt) or sizeof (exitmsg) chars. */
738 char swallowed[50];
739 /* Current position in swallowed. */
740 char *swallowed_p = swallowed;
741
742 int ch;
743 int ch_handled;
744 int old_timeout = timeout;
745 int old_immediate_quit = immediate_quit;
746
747 status->kind = TARGET_WAITKIND_EXITED;
748 status->value.integer = 0;
749
750 if (need_artificial_trap != 0)
751 {
752 status->kind = TARGET_WAITKIND_STOPPED;
753 status->value.sig = TARGET_SIGNAL_TRAP;
754 need_artificial_trap--;
755 return 0;
756 }
757
758 timeout = 0; /* Don't time out -- user program is running. */
759 immediate_quit = 1; /* Helps ability to QUIT */
760 while (1) {
761 QUIT; /* Let user quit and leave process running */
762 ch_handled = 0;
763 ch = readchar ();
764 if (ch == *bp) {
765 bp++;
766 if (*bp == '\0')
767 break;
768 ch_handled = 1;
769
770 *swallowed_p++ = ch;
771 } else
772 bp = bpt;
773 if (ch == *ep || *ep == '?') {
774 ep++;
775 if (*ep == '\0')
776 break;
777
778 if (!ch_handled)
779 *swallowed_p++ = ch;
780 ch_handled = 1;
781 } else
782 ep = exitmsg;
783 if (!ch_handled) {
784 char *p;
785 /* Print out any characters which have been swallowed. */
786 for (p = swallowed; p < swallowed_p; ++p)
787 putc (*p, stdout);
788 swallowed_p = swallowed;
789 putc (ch, stdout);
790 }
791 }
792 expect_prompt ();
793 if (*bp== '\0')
794 {
795 status->kind = TARGET_WAITKIND_STOPPED;
796 status->value.sig = TARGET_SIGNAL_TRAP;
797 }
798 else
799 {
800 status->kind = TARGET_WAITKIND_EXITED;
801 status->value.integer = 0;
802 }
803 timeout = old_timeout;
804 immediate_quit = old_immediate_quit;
805 return 0;
806 }
807
808 /* Return the name of register number REGNO
809 in the form input and output by adapt.
810
811 Returns a pointer to a static buffer containing the answer. */
812 static char *
813 get_reg_name (regno)
814 int regno;
815 {
816 static char buf[80];
817 if (regno >= GR96_REGNUM && regno < GR96_REGNUM + 32 )
818 sprintf (buf, "GR%03d", regno - GR96_REGNUM + 96);
819 #if defined(GR64_REGNUM)
820 else if (regno >= GR64_REGNUM && regno < GR64_REGNUM + 32 )
821 sprintf (buf, "GR%03d", regno - GR64_REGNUM + 64);
822 #endif
823 else if (regno >= LR0_REGNUM && regno < LR0_REGNUM + 128)
824 sprintf (buf, "LR%03d", regno - LR0_REGNUM);
825 else if (regno == Q_REGNUM)
826 strcpy (buf, "SR131");
827 else if (regno >= BP_REGNUM && regno <= CR_REGNUM)
828 sprintf (buf, "SR%03d", regno - BP_REGNUM + 133);
829 else if (regno == ALU_REGNUM)
830 strcpy (buf, "SR132");
831 else if (regno >= IPC_REGNUM && regno <= IPB_REGNUM)
832 sprintf (buf, "SR%03d", regno - IPC_REGNUM + 128);
833 else if (regno >= VAB_REGNUM && regno <= LRU_REGNUM) {
834 /* When a 29050 is in freeze-mode, read shadow pcs instead */
835 if ((regno >= NPC_REGNUM && regno <= PC2_REGNUM) && USE_SHADOW_PC)
836 sprintf (buf, "SR%03d", regno - NPC_REGNUM + 20);
837 else
838 sprintf (buf, "SR%03d", regno - VAB_REGNUM);
839 }
840 else if (regno == GR1_REGNUM)
841 strcpy (buf, "GR001");
842 return buf;
843 }
844
845 /* Read the remote registers. */
846
847 static void
848 adapt_fetch_registers ()
849 {
850 int reg_index;
851 int regnum_index;
852 char tempbuf[10];
853 int sreg_buf[16];
854 int i,j;
855
856 /*
857 * Global registers
858 */
859 #if defined(GR64_REGNUM)
860 write (adapt_desc, "dw gr64,gr95\r", 13);
861 for (reg_index = 64, regnum_index = GR64_REGNUM;
862 reg_index < 96;
863 reg_index += 4, regnum_index += 4)
864 {
865 sprintf (tempbuf, "GR%03d ", reg_index);
866 expect (tempbuf);
867 get_hex_regs (4, regnum_index);
868 expect ("\n");
869 }
870 #endif
871 write (adapt_desc, "dw gr96,gr127\r", 14);
872 for (reg_index = 96, regnum_index = GR96_REGNUM;
873 reg_index < 128;
874 reg_index += 4, regnum_index += 4)
875 {
876 sprintf (tempbuf, "GR%03d ", reg_index);
877 expect (tempbuf);
878 get_hex_regs (4, regnum_index);
879 expect ("\n");
880 }
881
882 /*
883 * Local registers
884 */
885 for (i = 0; i < 128; i += 32)
886 {
887 /* The PC has a tendency to hang if we get these
888 all in one fell swoop ("dw lr0,lr127"). */
889 sprintf (tempbuf, "dw lr%d\r", i);
890 write (adapt_desc, tempbuf, strlen (tempbuf));
891 for (reg_index = i, regnum_index = LR0_REGNUM + i;
892 reg_index < i + 32;
893 reg_index += 4, regnum_index += 4)
894 {
895 sprintf (tempbuf, "LR%03d ", reg_index);
896 expect (tempbuf);
897 get_hex_regs (4, regnum_index);
898 expect ("\n");
899 }
900 }
901
902 /*
903 * Special registers
904 */
905 sprintf (tempbuf, "dw sr0\r");
906 write (adapt_desc, tempbuf, strlen (tempbuf));
907 for (i=0 ; i<4 ; i++) { /* SR0 - SR14 */
908 sprintf (tempbuf, "SR%3d",i*4);
909 expect(tempbuf);
910 for (j=0 ; j < (i==3 ? 3 : 4) ; j++)
911 sreg_buf[i*4 + j] = get_hex_word();
912 }
913 expect_prompt();
914 /*
915 * Read the pcs individually if we are in freeze mode.
916 * See get_reg_name(), it translates the register names for the pcs to
917 * the names of the shadow pcs.
918 */
919 if (USE_SHADOW_PC) {
920 sreg_buf[10] = read_register(NPC_REGNUM); /* pc0 */
921 sreg_buf[11] = read_register(PC_REGNUM); /* pc1 */
922 sreg_buf[12] = read_register(PC2_REGNUM); /* pc2 */
923 }
924 for (i=0 ; i<14 ; i++) /* Supply vab -> lru */
925 supply_register(VAB_REGNUM+i, (char *) &sreg_buf[i]);
926 sprintf (tempbuf, "dw sr128\r");
927 write (adapt_desc, tempbuf, strlen (tempbuf));
928 for (i=0 ; i<2 ; i++) { /* SR128 - SR135 */
929 sprintf (tempbuf, "SR%3d",128 + i*4);
930 expect(tempbuf);
931 for (j=0 ; j<4 ; j++)
932 sreg_buf[i*4 + j] = get_hex_word();
933 }
934 expect_prompt();
935 supply_register(IPC_REGNUM,(char *) &sreg_buf[0]);
936 supply_register(IPA_REGNUM,(char *) &sreg_buf[1]);
937 supply_register(IPB_REGNUM,(char *) &sreg_buf[2]);
938 supply_register(Q_REGNUM, (char *) &sreg_buf[3]);
939 /* Skip ALU */
940 supply_register(BP_REGNUM, (char *) &sreg_buf[5]);
941 supply_register(FC_REGNUM, (char *) &sreg_buf[6]);
942 supply_register(CR_REGNUM, (char *) &sreg_buf[7]);
943
944 /* There doesn't seem to be any way to get these. */
945 {
946 int val = -1;
947 supply_register (FPE_REGNUM, (char *) &val);
948 supply_register (INTE_REGNUM, (char *) &val);
949 supply_register (FPS_REGNUM, (char *) &val);
950 supply_register (EXO_REGNUM, (char *) &val);
951 }
952
953 write (adapt_desc, "dw gr1,gr1\r", 11);
954 expect ("GR001 ");
955 get_hex_regs (1, GR1_REGNUM);
956 expect_prompt ();
957 }
958
959 /* Fetch register REGNO, or all registers if REGNO is -1.
960 */
961 static void
962 adapt_fetch_register (regno)
963 int regno;
964 {
965 if (regno == -1)
966 adapt_fetch_registers ();
967 else
968 {
969 char *name = get_reg_name (regno);
970 fprintf (adapt_stream, "dw %s,%s\r", name, name);
971 expect (name);
972 expect (" ");
973 get_hex_regs (1, regno);
974 expect_prompt ();
975 }
976 }
977
978 /* Store the remote registers from the contents of the block REGS. */
979
980 static void
981 adapt_store_registers ()
982 {
983 int i, j;
984
985 fprintf (adapt_stream, "s gr1,%x\r", read_register (GR1_REGNUM));
986 expect_prompt ();
987
988 #if defined(GR64_REGNUM)
989 for (j = 0; j < 32; j += 16)
990 {
991 fprintf (adapt_stream, "s gr%d,", j + 64);
992 for (i = 0; i < 15; ++i)
993 fprintf (adapt_stream, "%x,", read_register (GR64_REGNUM + j + i));
994 fprintf (adapt_stream, "%x\r", read_register (GR64_REGNUM + j + 15));
995 expect_prompt ();
996 }
997 #endif
998 for (j = 0; j < 32; j += 16)
999 {
1000 fprintf (adapt_stream, "s gr%d,", j + 96);
1001 for (i = 0; i < 15; ++i)
1002 fprintf (adapt_stream, "%x,", read_register (GR96_REGNUM + j + i));
1003 fprintf (adapt_stream, "%x\r", read_register (GR96_REGNUM + j + 15));
1004 expect_prompt ();
1005 }
1006
1007 for (j = 0; j < 128; j += 16)
1008 {
1009 fprintf (adapt_stream, "s lr%d,", j);
1010 for (i = 0; i < 15; ++i)
1011 fprintf (adapt_stream, "%x,", read_register (LR0_REGNUM + j + i));
1012 fprintf (adapt_stream, "%x\r", read_register (LR0_REGNUM + j + 15));
1013 expect_prompt ();
1014 }
1015
1016 fprintf (adapt_stream, "s sr128,%x,%x,%x\r", read_register (IPC_REGNUM),
1017 read_register (IPA_REGNUM), read_register (IPB_REGNUM));
1018 expect_prompt ();
1019 fprintf (adapt_stream, "s sr133,%x,%x,%x\r", read_register (BP_REGNUM),
1020 read_register (FC_REGNUM), read_register (CR_REGNUM));
1021 expect_prompt ();
1022 fprintf (adapt_stream, "s sr131,%x\r", read_register (Q_REGNUM));
1023 expect_prompt ();
1024 fprintf (adapt_stream, "s sr0,");
1025 for (i=0 ; i<7 ; ++i)
1026 fprintf (adapt_stream, "%x,", read_register (VAB_REGNUM + i));
1027 expect_prompt ();
1028 fprintf (adapt_stream, "s sr7,");
1029 for (i=7; i<14 ; ++i)
1030 fprintf (adapt_stream, "%x,", read_register (VAB_REGNUM + i));
1031 expect_prompt ();
1032 }
1033
1034 /* Store register REGNO, or all if REGNO == -1.
1035 Return errno value. */
1036 void
1037 adapt_store_register (regno)
1038 int regno;
1039 {
1040 /* printf("adapt_store_register() called.\n"); fflush(stdout); /* */
1041 if (regno == -1)
1042 adapt_store_registers ();
1043 else
1044 {
1045 char *name = get_reg_name (regno);
1046 fprintf (adapt_stream, "s %s,%x\r", name, read_register (regno));
1047 /* Setting GR1 changes the numbers of all the locals, so
1048 invalidate the register cache. Do this *after* calling
1049 read_register, because we want read_register to return the
1050 value that write_register has just stuffed into the registers
1051 array, not the value of the register fetched from the
1052 inferior. */
1053 if (regno == GR1_REGNUM)
1054 registers_changed ();
1055 expect_prompt ();
1056 }
1057 }
1058
1059 /* Get ready to modify the registers array. On machines which store
1060 individual registers, this doesn't need to do anything. On machines
1061 which store all the registers in one fell swoop, this makes sure
1062 that registers contains all the registers from the program being
1063 debugged. */
1064
1065 void
1066 adapt_prepare_to_store ()
1067 {
1068 /* Do nothing, since we can store individual regs */
1069 }
1070
1071 static CORE_ADDR
1072 translate_addr(addr)
1073 CORE_ADDR addr;
1074 {
1075 #if defined(KERNEL_DEBUGGING)
1076 /* Check for a virtual address in the kernel */
1077 /* Assume physical address of ublock is in paddr_u register */
1078 if (addr >= UVADDR) {
1079 /* PADDR_U register holds the physical address of the ublock */
1080 CORE_ADDR i = (CORE_ADDR)read_register(PADDR_U_REGNUM);
1081 return(i + addr - (CORE_ADDR)UVADDR);
1082 } else {
1083 return(addr);
1084 }
1085 #else
1086 return(addr);
1087 #endif
1088 }
1089
1090
1091 /* FIXME! Merge these two. */
1092 int
1093 adapt_xfer_inferior_memory (memaddr, myaddr, len, write)
1094 CORE_ADDR memaddr;
1095 char *myaddr;
1096 int len;
1097 int write;
1098 {
1099
1100 memaddr = translate_addr(memaddr);
1101
1102 if (write)
1103 return adapt_write_inferior_memory (memaddr, myaddr, len);
1104 else
1105 return adapt_read_inferior_memory (memaddr, myaddr, len);
1106 }
1107
1108 void
1109 adapt_files_info ()
1110 {
1111 printf_filtered("\tAttached to %s at %d baud and running program %s\n",
1112 dev_name, baudrate, prog_name);
1113 printf_filtered("\ton an %s processor.\n", processor_name[processor_type]);
1114 }
1115
1116 /* Copy LEN bytes of data from debugger memory at MYADDR
1117 to inferior's memory at MEMADDR. Returns errno value.
1118 * sb/sh instructions don't work on unaligned addresses, when TU=1.
1119 */
1120 int
1121 adapt_write_inferior_memory (memaddr, myaddr, len)
1122 CORE_ADDR memaddr;
1123 char *myaddr;
1124 int len;
1125 {
1126 int i;
1127 unsigned int cps;
1128
1129 /* Turn TU bit off so we can do 'sb' commands */
1130 cps = read_register(CPS_REGNUM);
1131 if (cps & 0x00000800)
1132 write_register(CPS_REGNUM,cps&~(0x00000800));
1133
1134 for (i = 0; i < len; i++)
1135 {
1136 if ((i % 16) == 0)
1137 fprintf (adapt_stream, "sb %x,", memaddr + i);
1138 if ((i % 16) == 15 || i == len - 1)
1139 {
1140 fprintf (adapt_stream, "%x\r", ((unsigned char *)myaddr)[i]);
1141 expect_prompt ();
1142 }
1143 else
1144 fprintf (adapt_stream, "%x,", ((unsigned char *)myaddr)[i]);
1145 }
1146 /* Restore the old value of cps if the TU bit was on */
1147 if (cps & 0x00000800)
1148 write_register(CPS_REGNUM,cps);
1149 return len;
1150 }
1151
1152 /* Read LEN bytes from inferior memory at MEMADDR. Put the result
1153 at debugger address MYADDR. Returns errno value. */
1154 int
1155 adapt_read_inferior_memory(memaddr, myaddr, len)
1156 CORE_ADDR memaddr;
1157 char *myaddr;
1158 int len;
1159 {
1160 int i;
1161
1162 /* Number of bytes read so far. */
1163 int count;
1164
1165 /* Starting address of this pass. */
1166 unsigned long startaddr;
1167
1168 /* Number of bytes to read in this pass. */
1169 int len_this_pass;
1170
1171 /* Note that this code works correctly if startaddr is just less
1172 than UINT_MAX (well, really CORE_ADDR_MAX if there was such a
1173 thing). That is, something like
1174 adapt_read_bytes (CORE_ADDR_MAX - 4, foo, 4)
1175 works--it never adds len to memaddr and gets 0. */
1176 /* However, something like
1177 adapt_read_bytes (CORE_ADDR_MAX - 3, foo, 4)
1178 doesn't need to work. Detect it and give up if there's an attempt
1179 to do that. */
1180
1181 if (((memaddr - 1) + len) < memaddr)
1182 return EIO;
1183
1184 startaddr = memaddr;
1185 count = 0;
1186 while (count < len)
1187 {
1188 len_this_pass = 16;
1189 if ((startaddr % 16) != 0)
1190 len_this_pass -= startaddr % 16;
1191 if (len_this_pass > (len - count))
1192 len_this_pass = (len - count);
1193
1194 fprintf (adapt_stream, "db %x,%x\r", startaddr,
1195 (startaddr - 1) + len_this_pass);
1196
1197 #ifdef NOTDEF /* Why do this */
1198 expect ("\n");
1199 /* Look for 8 hex digits. */
1200 i = 0;
1201 while (1)
1202 {
1203 if (isxdigit (readchar ()))
1204 ++i;
1205 else
1206 {
1207 expect_prompt ();
1208 error ("Hex digit expected from remote system.");
1209 }
1210 if (i >= 8)
1211 break;
1212 }
1213 #endif /* NOTDEF */
1214
1215 expect (" ");
1216
1217 for (i = 0; i < len_this_pass; i++)
1218 get_hex_byte (&myaddr[count++]);
1219
1220 expect_prompt ();
1221
1222 startaddr += len_this_pass;
1223 }
1224 return count;
1225 }
1226
1227 #define MAX_BREAKS 8
1228 static int num_brkpts=0;
1229 static int
1230 adapt_insert_breakpoint(addr, save)
1231 CORE_ADDR addr;
1232 char *save; /* Throw away, let adapt save instructions */
1233 {
1234 if (num_brkpts < MAX_BREAKS) {
1235 num_brkpts++;
1236 fprintf (adapt_stream, "B %x", addr);
1237 fprintf (adapt_stream, "\r");
1238 expect_prompt ();
1239 return(0); /* Success */
1240 } else {
1241 fprintf_filtered(gdb_stderr,
1242 "Too many break points, break point not installed\n");
1243 return(1); /* Failure */
1244 }
1245
1246 }
1247 static int
1248 adapt_remove_breakpoint(addr, save)
1249 CORE_ADDR addr;
1250 char *save; /* Throw away, let adapt save instructions */
1251 {
1252 if (num_brkpts > 0) {
1253 num_brkpts--;
1254 fprintf (adapt_stream, "BR %x", addr);
1255 fprintf (adapt_stream, "\r");
1256 fflush (adapt_stream);
1257 expect_prompt ();
1258 }
1259 return(0);
1260 }
1261
1262 /* Clear the adapts notion of what the break points are */
1263 static int
1264 adapt_clear_breakpoints()
1265 {
1266 if (adapt_stream) {
1267 fprintf (adapt_stream, "BR"); /* Clear all break points */
1268 fprintf (adapt_stream, "\r");
1269 fflush(adapt_stream);
1270 expect_prompt ();
1271 }
1272 num_brkpts = 0;
1273 }
1274 static void
1275 adapt_mourn()
1276 {
1277 adapt_clear_breakpoints();
1278 pop_target (); /* Pop back to no-child state */
1279 generic_mourn_inferior ();
1280 }
1281
1282 /* Display everthing we read in from the adapt until we match/see the
1283 * specified string
1284 */
1285 static int
1286 display_until(str)
1287 char *str;
1288 {
1289 int i=0,j,c;
1290
1291 while (c=readchar()) {
1292 if (c==str[i]) {
1293 i++;
1294 if (i == strlen(str)) return;
1295 } else {
1296 if (i) {
1297 for (j=0 ; j<i ; j++) /* Put everthing we matched */
1298 putchar(str[j]);
1299 i=0;
1300 }
1301 putchar(c);
1302 }
1303 }
1304
1305 }
1306
1307
1308 /* Put a command string, in args, out to the adapt. The adapt is assumed to
1309 be in raw mode, all writing/reading done through adapt_desc.
1310 Ouput from the adapt is placed on the users terminal until the
1311 prompt from the adapt is seen.
1312 FIXME: Can't handle commands that take input. */
1313
1314 void
1315 adapt_com (args, fromtty)
1316 char *args;
1317 int fromtty;
1318 {
1319 if (!adapt_stream) {
1320 printf_filtered("Adapt not open. Use the 'target' command to open.\n");
1321 return;
1322 }
1323
1324 /* Clear all input so only command relative output is displayed */
1325 slurp_input();
1326
1327 switch(islower(args[0]) ? toupper(args[0]) : args[0]) {
1328 default:
1329 printf_filtered("Unknown/Unimplemented adapt command '%s'\n",args);
1330 break;
1331 case 'G': /* Go, begin execution */
1332 write(adapt_desc,args,strlen(args));
1333 write(adapt_desc,"\r",1);
1334 expect_prompt();
1335 break;
1336 case 'B': /* Break points, B or BR */
1337 case 'C': /* Check current 29k status (running/halted) */
1338 case 'D': /* Display data/registers */
1339 case 'I': /* Input from i/o space */
1340 case 'J': /* Jam an instruction */
1341 case 'K': /* Kill, stop execution */
1342 case 'L': /* Disassemble */
1343 case 'O': /* Output to i/o space */
1344 case 'T': /* Trace */
1345 case 'P': /* Pulse an input line */
1346 case 'X': /* Examine special purpose registers */
1347 case 'Z': /* Display trace buffer */
1348 write(adapt_desc,args,strlen(args));
1349 write(adapt_desc,"\r",1);
1350 expect(args); /* Don't display the command */
1351 display_until("# ");
1352 break;
1353 /* Begin commands that take input in the form 'c x,y[,z...]' */
1354 case 'S': /* Set memory or register */
1355 if (strchr(args,',')) { /* Assume it is properly formatted */
1356 write(adapt_desc,args,strlen(args));
1357 write(adapt_desc,"\r",1);
1358 expect_prompt();
1359 }
1360 break;
1361 }
1362 }
1363
1364 /* Define the target subroutine names */
1365
1366 struct target_ops adapt_ops ;
1367
1368 static void
1369 init_adapt_ops(void)
1370 {
1371 adapt_ops.to_shortname = "adapt";
1372 adapt_ops.to_longname = "Remote AMD `Adapt' target";
1373 adapt_ops.to_doc = "Remote debug an AMD 290*0 using an `Adapt' monitor via RS232";
1374 adapt_ops.to_open = adapt_open;
1375 adapt_ops.to_close = adapt_close;
1376 adapt_ops.to_attach = adapt_attach;
1377 adapt_ops.to_post_attach = NULL;
1378 adapt_ops.to_require_attach = NULL;
1379 adapt_ops.to_detach = adapt_detach;
1380 adapt_ops.to_require_detach = NULL;
1381 adapt_ops.to_resume = adapt_resume;
1382 adapt_ops.to_wait = adapt_wait;
1383 adapt_ops.to_post_wait = NULL;
1384 adapt_ops.to_fetch_registers = adapt_fetch_register;
1385 adapt_ops.to_store_registers = adapt_store_register;
1386 adapt_ops.to_prepare_to_store = adapt_prepare_to_store;
1387 adapt_ops.to_xfer_memory = adapt_xfer_inferior_memory;
1388 adapt_ops.to_files_info = adapt_files_info;
1389 adapt_ops.to_insert_breakpoint = adapt_insert_breakpoint;
1390 adapt_ops.to_remove_breakpoint = adapt_remove_breakpoint;
1391 adapt_ops.to_terminal_init = 0;
1392 adapt_ops.to_terminal_inferior = 0;
1393 adapt_ops.to_terminal_ours_for_output = 0;
1394 adapt_ops.to_terminal_ours = 0;
1395 adapt_ops.to_terminal_info = 0;
1396 adapt_ops.to_kill = adapt_kill;
1397 adapt_ops.to_load = adapt_load;
1398 adapt_ops.to_lookup_symbol = 0;
1399 adapt_ops.to_create_inferior = adapt_create_inferior;
1400 adapt_ops.to_post_startup_inferior = NULL;
1401 adapt_ops.to_acknowledge_created_inferior = NULL;
1402 adapt_ops.to_clone_and_follow_inferior = NULL;
1403 adapt_ops.to_post_follow_inferior_by_clone = NULL;
1404 adapt_ops.to_insert_fork_catchpoint = NULL;
1405 adapt_ops.to_remove_fork_catchpoint = NULL;
1406 adapt_ops.to_insert_vfork_catchpoint = NULL;
1407 adapt_ops.to_remove_vfork_catchpoint = NULL;
1408 adapt_ops.to_has_forked = NULL;
1409 adapt_ops.to_has_vforked = NULL;
1410 adapt_ops.to_can_follow_vfork_prior_to_exec = NULL;
1411 adapt_ops.to_post_follow_vfork = NULL;
1412 adapt_ops.to_insert_exec_catchpoint = NULL;
1413 adapt_ops.to_remove_exec_catchpoint = NULL;
1414 adapt_ops.to_has_execd = NULL;
1415 adapt_ops.to_reported_exec_events_per_exec_call = NULL;
1416 adapt_ops.to_has_exited = NULL;
1417 adapt_ops.to_mourn_inferior = adapt_mourn;
1418 adapt_ops.to_can_run = 0;
1419 adapt_ops.to_notice_signals = 0;
1420 adapt_ops.to_thread_alive = 0;
1421 adapt_ops.to_stop = 0 ; /* process_stratum; */
1422 adapt_ops.to_pid_to_exec_file = NULL;
1423 adapt_ops.to_core_file_to_sym_file = NULL;
1424 adapt_ops.to_stratum = 0;
1425 adapt_ops.DONT_USE = 0 ;
1426 adapt_ops.to_has_all_memory = 1;
1427 adapt_ops.to_has_memory = 1;
1428 adapt_ops.to_has_stack = 1;
1429 adapt_ops.to_has_registers = 1;
1430 adapt_ops.to_has_execution = 0;
1431 adapt_ops.to_sections = 0;
1432 adapt_ops.to_sections_end = 0 ;
1433 adapt_ops.to_magic = OPS_MAGIC;
1434 } /* init_adapt_ops */
1435
1436 void
1437 _initialize_remote_adapt ()
1438 {
1439 init_adapt_ops() ;
1440 add_target (&adapt_ops);
1441 add_com ("adapt <command>", class_obscure, adapt_com,
1442 "Send a command to the AMD Adapt remote monitor.");
1443 }