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