xref: /dragonfly/contrib/gdb-7/gdb/stubs/sparc-stub.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
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
hex(unsigned char ch)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 *
getpacket(void)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
putpacket(unsigned char * buffer)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 *
mem2hex(unsigned char * mem,unsigned char * buf,int count,int may_fault)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 *
hex2mem(unsigned char * buf,unsigned char * mem,int count,int may_fault)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
set_debug_traps(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
set_mem_fault_trap(int enable)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
computeSignal(int tt)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
hexToInt(char ** ptr,int * intValue)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
handle_exception(unsigned long * registers)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
breakpoint(void)769 breakpoint (void)
770 {
771   if (!initialized)
772     return;
773 
774   asm("   .globl _breakinst
775 
776           _breakinst: ta 1
777       ");
778 }
779