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