import gdb-1999-08-23 snapshot
[external/binutils.git] / gdb / sparc-stub.c
1 /****************************************************************************
2
3                 THIS SOFTWARE IS NOT COPYRIGHTED
4
5    HP offers the following for use in the public domain.  HP makes no
6    warranty with regard to the software or it's performance and the
7    user accepts the software "AS IS" with all faults.
8
9    HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10    TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12
13 ****************************************************************************/
14
15 /****************************************************************************
16  *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
17  *
18  *  Module name: remcom.c $
19  *  Revision: 1.34 $
20  *  Date: 91/03/09 12:29:49 $
21  *  Contributor:     Lake Stevens Instrument Division$
22  *
23  *  Description:     low level support for gdb debugger. $
24  *
25  *  Considerations:  only works on target hardware $
26  *
27  *  Written by:      Glenn Engel $
28  *  ModuleState:     Experimental $
29  *
30  *  NOTES:           See Below $
31  *
32  *  Modified for SPARC by Stu Grossman, Cygnus Support.
33  *
34  *  This code has been extensively tested on the Fujitsu SPARClite demo board.
35  *
36  *  To enable debugger support, two things need to happen.  One, a
37  *  call to set_debug_traps() is necessary in order to allow any breakpoints
38  *  or error conditions to be properly intercepted and reported to gdb.
39  *  Two, a breakpoint needs to be generated to begin communication.  This
40  *  is most easily accomplished by a call to breakpoint().  Breakpoint()
41  *  simulates a breakpoint by executing a trap #1.
42  *
43  *************
44  *
45  *    The following gdb commands are supported:
46  *
47  * command          function                               Return value
48  *
49  *    g             return the value of the CPU registers  hex data or ENN
50  *    G             set the value of the CPU registers     OK or ENN
51  *
52  *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
53  *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
54  *
55  *    c             Resume at current address              SNN   ( signal NN)
56  *    cAA..AA       Continue at address AA..AA             SNN
57  *
58  *    s             Step one instruction                   SNN
59  *    sAA..AA       Step one instruction from AA..AA       SNN
60  *
61  *    k             kill
62  *
63  *    ?             What was the last sigval ?             SNN   (signal NN)
64  *
65  *    bBB..BB       Set baud rate to BB..BB                OK or BNN, then sets
66  *                                                         baud rate
67  *
68  * All commands and responses are sent with a packet which includes a
69  * checksum.  A packet consists of
70  *
71  * $<packet info>#<checksum>.
72  *
73  * where
74  * <packet info> :: <characters representing the command or response>
75  * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
76  *
77  * When a packet is received, it is first acknowledged with either '+' or '-'.
78  * '+' indicates a successful transfer.  '-' indicates a failed transfer.
79  *
80  * Example:
81  *
82  * Host:                  Reply:
83  * $m0,10#2a               +$00010203040506070809101112131415#42
84  *
85  ****************************************************************************/
86
87 #include <string.h>
88 #include <signal.h>
89
90 /************************************************************************
91  *
92  * external low-level support routines
93  */
94
95 extern void putDebugChar();     /* write a single character      */
96 extern int getDebugChar();      /* read and return a single char */
97
98 /************************************************************************/
99 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
100 /* at least NUMREGBYTES*2 are needed for register packets */
101 #define BUFMAX 2048
102
103 static int initialized = 0;     /* !0 means we've been initialized */
104
105 static void set_mem_fault_trap();
106
107 static const char hexchars[]="0123456789abcdef";
108
109 #define NUMREGS 72
110
111 /* Number of bytes of registers.  */
112 #define NUMREGBYTES (NUMREGS * 4)
113 enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
114                  O0, O1, O2, O3, O4, O5, SP, O7,
115                  L0, L1, L2, L3, L4, L5, L6, L7,
116                  I0, I1, I2, I3, I4, I5, FP, I7,
117
118                  F0, F1, F2, F3, F4, F5, F6, F7,
119                  F8, F9, F10, F11, F12, F13, F14, F15,
120                  F16, F17, F18, F19, F20, F21, F22, F23,
121                  F24, F25, F26, F27, F28, F29, F30, F31,
122                  Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR };
123
124 /***************************  ASSEMBLY CODE MACROS *************************/
125 /*                                                                         */
126
127 extern void trap_low();
128
129 asm("
130         .reserve trapstack, 1000 * 4, \"bss\", 8
131
132         .data
133         .align  4
134
135 in_trap_handler:
136         .word   0
137
138         .text
139         .align 4
140
141 ! This function is called when any SPARC trap (except window overflow or
142 ! underflow) occurs.  It makes sure that the invalid register window is still
143 ! available before jumping into C code.  It will also restore the world if you
144 ! return from handle_exception.
145
146         .globl _trap_low
147 _trap_low:
148         mov     %psr, %l0
149         mov     %wim, %l3
150
151         srl     %l3, %l0, %l4           ! wim >> cwp
152         cmp     %l4, 1
153         bne     window_fine             ! Branch if not in the invalid window
154         nop
155
156 ! Handle window overflow
157
158         mov     %g1, %l4                ! Save g1, we use it to hold the wim
159         srl     %l3, 1, %g1             ! Rotate wim right
160         tst     %g1
161         bg      good_wim                ! Branch if new wim is non-zero
162         nop
163
164 ! At this point, we need to bring a 1 into the high order bit of the wim.
165 ! Since we don't want to make any assumptions about the number of register
166 ! windows, we figure it out dynamically so as to setup the wim correctly.
167
168         not     %g1                     ! Fill g1 with ones
169         mov     %g1, %wim               ! Fill the wim with ones
170         nop
171         nop
172         nop
173         mov     %wim, %g1               ! Read back the wim
174         inc     %g1                     ! Now g1 has 1 just to left of wim
175         srl     %g1, 1, %g1             ! Now put 1 at top of wim
176         mov     %g0, %wim               ! Clear wim so that subsequent save
177         nop                             !  won't trap
178         nop
179         nop
180
181 good_wim:
182         save    %g0, %g0, %g0           ! Slip into next window
183         mov     %g1, %wim               ! Install the new wim
184
185         std     %l0, [%sp + 0 * 4]      ! save L & I registers
186         std     %l2, [%sp + 2 * 4]
187         std     %l4, [%sp + 4 * 4]
188         std     %l6, [%sp + 6 * 4]
189
190         std     %i0, [%sp + 8 * 4]
191         std     %i2, [%sp + 10 * 4]
192         std     %i4, [%sp + 12 * 4]
193         std     %i6, [%sp + 14 * 4]
194
195         restore                         ! Go back to trap window.
196         mov     %l4, %g1                ! Restore %g1
197
198 window_fine:
199         sethi   %hi(in_trap_handler), %l4
200         ld      [%lo(in_trap_handler) + %l4], %l5
201         tst     %l5
202         bg      recursive_trap
203         inc     %l5
204
205         set     trapstack+1000*4, %sp   ! Switch to trap stack
206
207 recursive_trap:
208         st      %l5, [%lo(in_trap_handler) + %l4]
209         sub     %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals
210                                         ! + hidden arg + arg spill
211                                         ! + doubleword alignment
212                                         ! + registers[72] local var
213
214         std     %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
215         std     %g2, [%sp + (24 + 2) * 4]
216         std     %g4, [%sp + (24 + 4) * 4]
217         std     %g6, [%sp + (24 + 6) * 4]
218
219         std     %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
220         std     %i2, [%sp + (24 + 10) * 4]
221         std     %i4, [%sp + (24 + 12) * 4]
222         std     %i6, [%sp + (24 + 14) * 4]
223                                         ! F0->F31 not implemented
224         mov     %y, %l4
225         mov     %tbr, %l5
226         st      %l4, [%sp + (24 + 64) * 4] ! Y
227         st      %l0, [%sp + (24 + 65) * 4] ! PSR
228         st      %l3, [%sp + (24 + 66) * 4] ! WIM
229         st      %l5, [%sp + (24 + 67) * 4] ! TBR
230         st      %l1, [%sp + (24 + 68) * 4] ! PC
231         st      %l2, [%sp + (24 + 69) * 4] ! NPC
232
233                                         ! CPSR and FPSR not impl
234
235         or      %l0, 0xf20, %l4
236         mov     %l4, %psr               ! Turn on traps, disable interrupts
237
238         call    _handle_exception
239         add     %sp, 24 * 4, %o0        ! Pass address of registers
240
241 ! Reload all of the registers that aren't on the stack
242
243         ld      [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
244         ldd     [%sp + (24 + 2) * 4], %g2
245         ldd     [%sp + (24 + 4) * 4], %g4
246         ldd     [%sp + (24 + 6) * 4], %g6
247
248         ldd     [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
249         ldd     [%sp + (24 + 10) * 4], %i2
250         ldd     [%sp + (24 + 12) * 4], %i4
251         ldd     [%sp + (24 + 14) * 4], %i6
252
253         ldd     [%sp + (24 + 64) * 4], %l0 ! Y & PSR
254         ldd     [%sp + (24 + 68) * 4], %l2 ! PC & NPC
255
256         restore                         ! Ensure that previous window is valid
257         save    %g0, %g0, %g0           !  by causing a window_underflow trap
258
259         mov     %l0, %y
260         mov     %l1, %psr               ! Make sure that traps are disabled
261                                         ! for rett
262
263         sethi   %hi(in_trap_handler), %l4
264         ld      [%lo(in_trap_handler) + %l4], %l5
265         dec     %l5
266         st      %l5, [%lo(in_trap_handler) + %l4]
267
268         jmpl    %l2, %g0                ! Restore old PC
269         rett    %l3                     ! Restore old nPC
270 ");
271
272 /* Convert ch from a hex digit to an int */
273
274 static int
275 hex(ch)
276      unsigned char ch;
277 {
278   if (ch >= 'a' && ch <= 'f')
279     return ch-'a'+10;
280   if (ch >= '0' && ch <= '9')
281     return ch-'0';
282   if (ch >= 'A' && ch <= 'F')
283     return ch-'A'+10;
284   return -1;
285 }
286
287 /* scan for the sequence $<data>#<checksum>     */
288
289 static void
290 getpacket(buffer)
291      char *buffer;
292 {
293   unsigned char checksum;
294   unsigned char xmitcsum;
295   int i;
296   int count;
297   unsigned char ch;
298
299   do
300     {
301       /* wait around for the start character, ignore all other characters */
302       while ((ch = (getDebugChar() & 0x7f)) != '$') ;
303
304       checksum = 0;
305       xmitcsum = -1;
306
307       count = 0;
308
309       /* now, read until a # or end of buffer is found */
310       while (count < BUFMAX)
311         {
312           ch = getDebugChar() & 0x7f;
313           if (ch == '#')
314             break;
315           checksum = checksum + ch;
316           buffer[count] = ch;
317           count = count + 1;
318         }
319
320       if (count >= BUFMAX)
321         continue;
322
323       buffer[count] = 0;
324
325       if (ch == '#')
326         {
327           xmitcsum = hex(getDebugChar() & 0x7f) << 4;
328           xmitcsum |= hex(getDebugChar() & 0x7f);
329 #if 0
330           /* Humans shouldn't have to figure out checksums to type to it. */
331           putDebugChar ('+');
332           return;
333 #endif
334           if (checksum != xmitcsum)
335             putDebugChar('-');  /* failed checksum */
336           else
337             {
338               putDebugChar('+'); /* successful transfer */
339               /* if a sequence char is present, reply the sequence ID */
340               if (buffer[2] == ':')
341                 {
342                   putDebugChar(buffer[0]);
343                   putDebugChar(buffer[1]);
344                   /* remove sequence chars from buffer */
345                   count = strlen(buffer);
346                   for (i=3; i <= count; i++)
347                     buffer[i-3] = buffer[i];
348                 }
349             }
350         }
351     }
352   while (checksum != xmitcsum);
353 }
354
355 /* send the packet in buffer.  */
356
357 static void
358 putpacket(buffer)
359      unsigned char *buffer;
360 {
361   unsigned char checksum;
362   int count;
363   unsigned char ch;
364
365   /*  $<packet info>#<checksum>. */
366   do
367     {
368       putDebugChar('$');
369       checksum = 0;
370       count = 0;
371
372       while (ch = buffer[count])
373         {
374           putDebugChar(ch);
375           checksum += ch;
376           count += 1;
377         }
378
379       putDebugChar('#');
380       putDebugChar(hexchars[checksum >> 4]);
381       putDebugChar(hexchars[checksum & 0xf]);
382
383     }
384   while ((getDebugChar() & 0x7f) != '+');
385 }
386
387 static char remcomInBuffer[BUFMAX];
388 static char remcomOutBuffer[BUFMAX];
389
390 /* Indicate to caller of mem2hex or hex2mem that there has been an
391    error.  */
392 static volatile int mem_err = 0;
393
394 /* Convert the memory pointed to by mem into hex, placing result in buf.
395  * Return a pointer to the last char put in buf (null), in case of mem fault,
396  * return 0.
397  * If MAY_FAULT is non-zero, then we will handle memory faults by returning
398  * a 0, else treat a fault like any other fault in the stub.
399  */
400
401 static unsigned char *
402 mem2hex(mem, buf, count, may_fault)
403      unsigned char *mem;
404      unsigned char *buf;
405      int count;
406      int may_fault;
407 {
408   unsigned char ch;
409
410   set_mem_fault_trap(may_fault);
411
412   while (count-- > 0)
413     {
414       ch = *mem++;
415       if (mem_err)
416         return 0;
417       *buf++ = hexchars[ch >> 4];
418       *buf++ = hexchars[ch & 0xf];
419     }
420
421   *buf = 0;
422
423   set_mem_fault_trap(0);
424
425   return buf;
426 }
427
428 /* convert the hex array pointed to by buf into binary to be placed in mem
429  * return a pointer to the character AFTER the last byte written */
430
431 static char *
432 hex2mem(buf, mem, count, may_fault)
433      unsigned char *buf;
434      unsigned char *mem;
435      int count;
436      int may_fault;
437 {
438   int i;
439   unsigned char ch;
440
441   set_mem_fault_trap(may_fault);
442
443   for (i=0; i<count; i++)
444     {
445       ch = hex(*buf++) << 4;
446       ch |= hex(*buf++);
447       *mem++ = ch;
448       if (mem_err)
449         return 0;
450     }
451
452   set_mem_fault_trap(0);
453
454   return mem;
455 }
456
457 /* This table contains the mapping between SPARC hardware trap types, and
458    signals, which are primarily what GDB understands.  It also indicates
459    which hardware traps we need to commandeer when initializing the stub. */
460
461 static struct hard_trap_info
462 {
463   unsigned char tt;             /* Trap type code for SPARClite */
464   unsigned char signo;          /* Signal that we map this trap into */
465 } hard_trap_info[] = {
466   {1, SIGSEGV},                 /* instruction access error */
467   {2, SIGILL},                  /* privileged instruction */
468   {3, SIGILL},                  /* illegal instruction */
469   {4, SIGEMT},                  /* fp disabled */
470   {36, SIGEMT},                 /* cp disabled */
471   {7, SIGBUS},                  /* mem address not aligned */
472   {9, SIGSEGV},                 /* data access exception */
473   {10, SIGEMT},                 /* tag overflow */
474   {128+1, SIGTRAP},             /* ta 1 - normal breakpoint instruction */
475   {0, 0}                        /* Must be last */
476 };
477
478 /* Set up exception handlers for tracing and breakpoints */
479
480 void
481 set_debug_traps()
482 {
483   struct hard_trap_info *ht;
484
485   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
486     exceptionHandler(ht->tt, trap_low);
487
488   initialized = 1;
489 }
490
491 asm ("
492 ! Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
493 ! assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
494 ! 0 would ever contain code that could mem fault.  This routine will skip
495 ! past the faulting instruction after setting mem_err.
496
497         .text
498         .align 4
499
500 _fltr_set_mem_err:
501         sethi %hi(_mem_err), %l0
502         st %l1, [%l0 + %lo(_mem_err)]
503         jmpl %l2, %g0
504         rett %l2+4
505 ");
506
507 static void
508 set_mem_fault_trap(enable)
509      int enable;
510 {
511   extern void fltr_set_mem_err();
512   mem_err = 0;
513
514   if (enable)
515     exceptionHandler(9, fltr_set_mem_err);
516   else
517     exceptionHandler(9, trap_low);
518 }
519
520 /* Convert the SPARC hardware trap type code to a unix signal number. */
521
522 static int
523 computeSignal(tt)
524      int tt;
525 {
526   struct hard_trap_info *ht;
527
528   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
529     if (ht->tt == tt)
530       return ht->signo;
531
532   return SIGHUP;                /* default for things we don't know about */
533 }
534
535 /*
536  * While we find nice hex chars, build an int.
537  * Return number of chars processed.
538  */
539
540 static int
541 hexToInt(char **ptr, int *intValue)
542 {
543   int numChars = 0;
544   int hexValue;
545
546   *intValue = 0;
547
548   while (**ptr)
549     {
550       hexValue = hex(**ptr);
551       if (hexValue < 0)
552         break;
553
554       *intValue = (*intValue << 4) | hexValue;
555       numChars ++;
556
557       (*ptr)++;
558     }
559
560   return (numChars);
561 }
562
563 /*
564  * This function does all command procesing for interfacing to gdb.  It
565  * returns 1 if you should skip the instruction at the trap address, 0
566  * otherwise.
567  */
568
569 extern void breakinst();
570
571 static void
572 handle_exception (registers)
573      unsigned long *registers;
574 {
575   int tt;                       /* Trap type */
576   int sigval;
577   int addr;
578   int length;
579   char *ptr;
580   unsigned long *sp;
581
582 /* First, we must force all of the windows to be spilled out */
583
584   asm(" save %sp, -64, %sp
585         save %sp, -64, %sp
586         save %sp, -64, %sp
587         save %sp, -64, %sp
588         save %sp, -64, %sp
589         save %sp, -64, %sp
590         save %sp, -64, %sp
591         save %sp, -64, %sp
592         restore
593         restore
594         restore
595         restore
596         restore
597         restore
598         restore
599         restore
600 ");
601
602   if (registers[PC] == (unsigned long)breakinst)
603     {
604       registers[PC] = registers[NPC];
605       registers[NPC] += 4;
606     }
607
608   sp = (unsigned long *)registers[SP];
609
610   tt = (registers[TBR] >> 4) & 0xff;
611
612   /* reply to host that an exception has occurred */
613   sigval = computeSignal(tt);
614   ptr = remcomOutBuffer;
615
616   *ptr++ = 'T';
617   *ptr++ = hexchars[sigval >> 4];
618   *ptr++ = hexchars[sigval & 0xf];
619
620   *ptr++ = hexchars[PC >> 4];
621   *ptr++ = hexchars[PC & 0xf];
622   *ptr++ = ':';
623   ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
624   *ptr++ = ';';
625
626   *ptr++ = hexchars[FP >> 4];
627   *ptr++ = hexchars[FP & 0xf];
628   *ptr++ = ':';
629   ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
630   *ptr++ = ';';
631
632   *ptr++ = hexchars[SP >> 4];
633   *ptr++ = hexchars[SP & 0xf];
634   *ptr++ = ':';
635   ptr = mem2hex((char *)&sp, ptr, 4, 0);
636   *ptr++ = ';';
637
638   *ptr++ = hexchars[NPC >> 4];
639   *ptr++ = hexchars[NPC & 0xf];
640   *ptr++ = ':';
641   ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
642   *ptr++ = ';';
643
644   *ptr++ = hexchars[O7 >> 4];
645   *ptr++ = hexchars[O7 & 0xf];
646   *ptr++ = ':';
647   ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
648   *ptr++ = ';';
649
650   *ptr++ = 0;
651
652   putpacket(remcomOutBuffer);
653
654   while (1)
655     {
656       remcomOutBuffer[0] = 0;
657
658       getpacket(remcomInBuffer);
659       switch (remcomInBuffer[0])
660         {
661         case '?':
662           remcomOutBuffer[0] = 'S';
663           remcomOutBuffer[1] = hexchars[sigval >> 4];
664           remcomOutBuffer[2] = hexchars[sigval & 0xf];
665           remcomOutBuffer[3] = 0;
666           break;
667
668         case 'd':
669                                 /* toggle debug flag */
670           break;
671
672         case 'g':               /* return the value of the CPU registers */
673           {
674             ptr = remcomOutBuffer;
675             ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
676             ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
677             memset(ptr, '0', 32 * 8); /* Floating point */
678             mem2hex((char *)&registers[Y],
679                     ptr + 32 * 4 * 2,
680                     8 * 4,
681                     0);         /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
682           }
683           break;
684
685         case 'G':          /* set the value of the CPU registers - return OK */
686           {
687             unsigned long *newsp, psr;
688
689             psr = registers[PSR];
690
691             ptr = &remcomInBuffer[1];
692             hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
693             hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
694             hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y],
695                     8 * 4, 0);  /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
696
697             /* See if the stack pointer has moved.  If so, then copy the saved
698                locals and ins to the new location.  This keeps the window
699                overflow and underflow routines happy.  */
700
701             newsp = (unsigned long *)registers[SP];
702             if (sp != newsp)
703               sp = memcpy(newsp, sp, 16 * 4);
704
705             /* Don't allow CWP to be modified. */
706
707             if (psr != registers[PSR])
708               registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
709
710             strcpy(remcomOutBuffer,"OK");
711           }
712           break;
713
714         case 'm':         /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
715           /* Try to read %x,%x.  */
716
717           ptr = &remcomInBuffer[1];
718
719           if (hexToInt(&ptr, &addr)
720               && *ptr++ == ','
721               && hexToInt(&ptr, &length))
722             {
723               if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
724                 break;
725
726               strcpy (remcomOutBuffer, "E03");
727             }
728           else
729             strcpy(remcomOutBuffer,"E01");
730           break;
731
732         case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
733           /* Try to read '%x,%x:'.  */
734
735           ptr = &remcomInBuffer[1];
736
737           if (hexToInt(&ptr, &addr)
738               && *ptr++ == ','
739               && hexToInt(&ptr, &length)
740               && *ptr++ == ':')
741             {
742               if (hex2mem(ptr, (char *)addr, length, 1))
743                 strcpy(remcomOutBuffer, "OK");
744               else
745                 strcpy(remcomOutBuffer, "E03");
746             }
747           else
748             strcpy(remcomOutBuffer, "E02");
749           break;
750
751         case 'c':    /* cAA..AA    Continue at address AA..AA(optional) */
752           /* try to read optional parameter, pc unchanged if no parm */
753
754           ptr = &remcomInBuffer[1];
755           if (hexToInt(&ptr, &addr))
756             {
757               registers[PC] = addr;
758               registers[NPC] = addr + 4;
759             }
760
761 /* Need to flush the instruction cache here, as we may have deposited a
762    breakpoint, and the icache probably has no way of knowing that a data ref to
763    some location may have changed something that is in the instruction cache.
764  */
765
766           flush_i_cache();
767           return;
768
769           /* kill the program */
770         case 'k' :              /* do nothing */
771           break;
772 #if 0
773         case 't':               /* Test feature */
774           asm (" std %f30,[%sp]");
775           break;
776 #endif
777         case 'r':               /* Reset */
778           asm ("call 0
779                 nop ");
780           break;
781
782 #if 0
783 Disabled until we can unscrew this properly
784
785         case 'b':         /* bBB...  Set baud rate to BB... */
786           {
787             int baudrate;
788             extern void set_timer_3();
789
790             ptr = &remcomInBuffer[1];
791             if (!hexToInt(&ptr, &baudrate))
792               {
793                 strcpy(remcomOutBuffer,"B01");
794                 break;
795               }
796
797             /* Convert baud rate to uart clock divider */
798             switch (baudrate)
799               {
800               case 38400:
801                 baudrate = 16;
802                 break;
803               case 19200:
804                 baudrate = 33;
805                 break;
806               case 9600:
807                 baudrate = 65;
808                 break;
809               default:
810                 strcpy(remcomOutBuffer,"B02");
811                 goto x1;
812               }
813
814             putpacket("OK");    /* Ack before changing speed */
815             set_timer_3(baudrate); /* Set it */
816           }
817 x1:       break;
818 #endif
819         }                       /* switch */
820
821       /* reply to the request */
822       putpacket(remcomOutBuffer);
823     }
824 }
825
826 /* This function will generate a breakpoint exception.  It is used at the
827    beginning of a program to sync up with a debugger and can be used
828    otherwise as a quick means to stop program execution and "break" into
829    the debugger. */
830
831 void
832 breakpoint()
833 {
834   if (!initialized)
835     return;
836
837   asm(" .globl _breakinst
838
839         _breakinst: ta 1
840       ");
841 }