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