Initial creation of sourceware repository
[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   /* In case GDB is started before us, ack any packets (presumably
489      "$?#xx") sitting there.  */
490
491   putDebugChar ('+');
492
493   initialized = 1;
494 }
495
496 asm ("
497 ! Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
498 ! assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
499 ! 0 would ever contain code that could mem fault.  This routine will skip
500 ! past the faulting instruction after setting mem_err.
501
502         .text
503         .align 4
504
505 _fltr_set_mem_err:
506         sethi %hi(_mem_err), %l0
507         st %l1, [%l0 + %lo(_mem_err)]
508         jmpl %l2, %g0
509         rett %l2+4
510 ");
511
512 static void
513 set_mem_fault_trap(enable)
514      int enable;
515 {
516   extern void fltr_set_mem_err();
517   mem_err = 0;
518
519   if (enable)
520     exceptionHandler(9, fltr_set_mem_err);
521   else
522     exceptionHandler(9, trap_low);
523 }
524
525 /* Convert the SPARC hardware trap type code to a unix signal number. */
526
527 static int
528 computeSignal(tt)
529      int tt;
530 {
531   struct hard_trap_info *ht;
532
533   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
534     if (ht->tt == tt)
535       return ht->signo;
536
537   return SIGHUP;                /* default for things we don't know about */
538 }
539
540 /*
541  * While we find nice hex chars, build an int.
542  * Return number of chars processed.
543  */
544
545 static int
546 hexToInt(char **ptr, int *intValue)
547 {
548   int numChars = 0;
549   int hexValue;
550
551   *intValue = 0;
552
553   while (**ptr)
554     {
555       hexValue = hex(**ptr);
556       if (hexValue < 0)
557         break;
558
559       *intValue = (*intValue << 4) | hexValue;
560       numChars ++;
561
562       (*ptr)++;
563     }
564
565   return (numChars);
566 }
567
568 /*
569  * This function does all command procesing for interfacing to gdb.  It
570  * returns 1 if you should skip the instruction at the trap address, 0
571  * otherwise.
572  */
573
574 extern void breakinst();
575
576 static void
577 handle_exception (registers)
578      unsigned long *registers;
579 {
580   int tt;                       /* Trap type */
581   int sigval;
582   int addr;
583   int length;
584   char *ptr;
585   unsigned long *sp;
586
587 /* First, we must force all of the windows to be spilled out */
588
589   asm(" save %sp, -64, %sp
590         save %sp, -64, %sp
591         save %sp, -64, %sp
592         save %sp, -64, %sp
593         save %sp, -64, %sp
594         save %sp, -64, %sp
595         save %sp, -64, %sp
596         save %sp, -64, %sp
597         restore
598         restore
599         restore
600         restore
601         restore
602         restore
603         restore
604         restore
605 ");
606
607   if (registers[PC] == (unsigned long)breakinst)
608     {
609       registers[PC] = registers[NPC];
610       registers[NPC] += 4;
611     }
612
613   sp = (unsigned long *)registers[SP];
614
615   tt = (registers[TBR] >> 4) & 0xff;
616
617   /* reply to host that an exception has occurred */
618   sigval = computeSignal(tt);
619   ptr = remcomOutBuffer;
620
621   *ptr++ = 'T';
622   *ptr++ = hexchars[sigval >> 4];
623   *ptr++ = hexchars[sigval & 0xf];
624
625   *ptr++ = hexchars[PC >> 4];
626   *ptr++ = hexchars[PC & 0xf];
627   *ptr++ = ':';
628   ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
629   *ptr++ = ';';
630
631   *ptr++ = hexchars[FP >> 4];
632   *ptr++ = hexchars[FP & 0xf];
633   *ptr++ = ':';
634   ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
635   *ptr++ = ';';
636
637   *ptr++ = hexchars[SP >> 4];
638   *ptr++ = hexchars[SP & 0xf];
639   *ptr++ = ':';
640   ptr = mem2hex((char *)&sp, ptr, 4, 0);
641   *ptr++ = ';';
642
643   *ptr++ = hexchars[NPC >> 4];
644   *ptr++ = hexchars[NPC & 0xf];
645   *ptr++ = ':';
646   ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
647   *ptr++ = ';';
648
649   *ptr++ = hexchars[O7 >> 4];
650   *ptr++ = hexchars[O7 & 0xf];
651   *ptr++ = ':';
652   ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
653   *ptr++ = ';';
654
655   *ptr++ = 0;
656
657   putpacket(remcomOutBuffer);
658
659   while (1)
660     {
661       remcomOutBuffer[0] = 0;
662
663       getpacket(remcomInBuffer);
664       switch (remcomInBuffer[0])
665         {
666         case '?':
667           remcomOutBuffer[0] = 'S';
668           remcomOutBuffer[1] = hexchars[sigval >> 4];
669           remcomOutBuffer[2] = hexchars[sigval & 0xf];
670           remcomOutBuffer[3] = 0;
671           break;
672
673         case 'd':
674                                 /* toggle debug flag */
675           break;
676
677         case 'g':               /* return the value of the CPU registers */
678           {
679             ptr = remcomOutBuffer;
680             ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
681             ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
682             memset(ptr, '0', 32 * 8); /* Floating point */
683             mem2hex((char *)&registers[Y],
684                     ptr + 32 * 4 * 2,
685                     8 * 4,
686                     0);         /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
687           }
688           break;
689
690         case 'G':          /* set the value of the CPU registers - return OK */
691           {
692             unsigned long *newsp, psr;
693
694             psr = registers[PSR];
695
696             ptr = &remcomInBuffer[1];
697             hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
698             hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
699             hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y],
700                     8 * 4, 0);  /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
701
702             /* See if the stack pointer has moved.  If so, then copy the saved
703                locals and ins to the new location.  This keeps the window
704                overflow and underflow routines happy.  */
705
706             newsp = (unsigned long *)registers[SP];
707             if (sp != newsp)
708               sp = memcpy(newsp, sp, 16 * 4);
709
710             /* Don't allow CWP to be modified. */
711
712             if (psr != registers[PSR])
713               registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
714
715             strcpy(remcomOutBuffer,"OK");
716           }
717           break;
718
719         case 'm':         /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
720           /* Try to read %x,%x.  */
721
722           ptr = &remcomInBuffer[1];
723
724           if (hexToInt(&ptr, &addr)
725               && *ptr++ == ','
726               && hexToInt(&ptr, &length))
727             {
728               if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
729                 break;
730
731               strcpy (remcomOutBuffer, "E03");
732             }
733           else
734             strcpy(remcomOutBuffer,"E01");
735           break;
736
737         case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
738           /* Try to read '%x,%x:'.  */
739
740           ptr = &remcomInBuffer[1];
741
742           if (hexToInt(&ptr, &addr)
743               && *ptr++ == ','
744               && hexToInt(&ptr, &length)
745               && *ptr++ == ':')
746             {
747               if (hex2mem(ptr, (char *)addr, length, 1))
748                 strcpy(remcomOutBuffer, "OK");
749               else
750                 strcpy(remcomOutBuffer, "E03");
751             }
752           else
753             strcpy(remcomOutBuffer, "E02");
754           break;
755
756         case 'c':    /* cAA..AA    Continue at address AA..AA(optional) */
757           /* try to read optional parameter, pc unchanged if no parm */
758
759           ptr = &remcomInBuffer[1];
760           if (hexToInt(&ptr, &addr))
761             {
762               registers[PC] = addr;
763               registers[NPC] = addr + 4;
764             }
765
766 /* Need to flush the instruction cache here, as we may have deposited a
767    breakpoint, and the icache probably has no way of knowing that a data ref to
768    some location may have changed something that is in the instruction cache.
769  */
770
771           flush_i_cache();
772           return;
773
774           /* kill the program */
775         case 'k' :              /* do nothing */
776           break;
777 #if 0
778         case 't':               /* Test feature */
779           asm (" std %f30,[%sp]");
780           break;
781 #endif
782         case 'r':               /* Reset */
783           asm ("call 0
784                 nop ");
785           break;
786
787 #if 0
788 Disabled until we can unscrew this properly
789
790         case 'b':         /* bBB...  Set baud rate to BB... */
791           {
792             int baudrate;
793             extern void set_timer_3();
794
795             ptr = &remcomInBuffer[1];
796             if (!hexToInt(&ptr, &baudrate))
797               {
798                 strcpy(remcomOutBuffer,"B01");
799                 break;
800               }
801
802             /* Convert baud rate to uart clock divider */
803             switch (baudrate)
804               {
805               case 38400:
806                 baudrate = 16;
807                 break;
808               case 19200:
809                 baudrate = 33;
810                 break;
811               case 9600:
812                 baudrate = 65;
813                 break;
814               default:
815                 strcpy(remcomOutBuffer,"B02");
816                 goto x1;
817               }
818
819             putpacket("OK");    /* Ack before changing speed */
820             set_timer_3(baudrate); /* Set it */
821           }
822 x1:       break;
823 #endif
824         }                       /* switch */
825
826       /* reply to the request */
827       putpacket(remcomOutBuffer);
828     }
829 }
830
831 /* This function will generate a breakpoint exception.  It is used at the
832    beginning of a program to sync up with a debugger and can be used
833    otherwise as a quick means to stop program execution and "break" into
834    the debugger. */
835
836 void
837 breakpoint()
838 {
839   if (!initialized)
840     return;
841
842   asm(" .globl _breakinst
843
844         _breakinst: ta 1
845       ");
846 }