* mn10300.igen (OP_F0F4): Need to load contents of register AN0
[platform/upstream/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 putDebugChar();   /* write a single character      */
96 extern 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           if (! putDebugChar(ch))
375             return;
376           checksum += ch;
377           count += 1;
378         }
379
380       putDebugChar('#');
381       putDebugChar(hexchars[checksum >> 4]);
382       putDebugChar(hexchars[checksum & 0xf]);
383
384     }
385   while ((getDebugChar() & 0x7f) != '+');
386 }
387
388 static char remcomInBuffer[BUFMAX];
389 static char remcomOutBuffer[BUFMAX];
390
391 /* Indicate to caller of mem2hex or hex2mem that there has been an
392    error.  */
393 static volatile int mem_err = 0;
394
395 /* Convert the memory pointed to by mem into hex, placing result in buf.
396  * Return a pointer to the last char put in buf (null), in case of mem fault,
397  * return 0.
398  * If MAY_FAULT is non-zero, then we will handle memory faults by returning
399  * a 0, else treat a fault like any other fault in the stub.
400  */
401
402 static unsigned char *
403 mem2hex(mem, buf, count, may_fault)
404      unsigned char *mem;
405      unsigned char *buf;
406      int count;
407      int may_fault;
408 {
409   unsigned char ch;
410
411   set_mem_fault_trap(may_fault);
412
413   while (count-- > 0)
414     {
415       ch = *mem++;
416       if (mem_err)
417         return 0;
418       *buf++ = hexchars[ch >> 4];
419       *buf++ = hexchars[ch & 0xf];
420     }
421
422   *buf = 0;
423
424   set_mem_fault_trap(0);
425
426   return buf;
427 }
428
429 /* convert the hex array pointed to by buf into binary to be placed in mem
430  * return a pointer to the character AFTER the last byte written */
431
432 static char *
433 hex2mem(buf, mem, count, may_fault)
434      unsigned char *buf;
435      unsigned char *mem;
436      int count;
437      int may_fault;
438 {
439   int i;
440   unsigned char ch;
441
442   set_mem_fault_trap(may_fault);
443
444   for (i=0; i<count; i++)
445     {
446       ch = hex(*buf++) << 4;
447       ch |= hex(*buf++);
448       *mem++ = ch;
449       if (mem_err)
450         return 0;
451     }
452
453   set_mem_fault_trap(0);
454
455   return mem;
456 }
457
458 /* This table contains the mapping between SPARC hardware trap types, and
459    signals, which are primarily what GDB understands.  It also indicates
460    which hardware traps we need to commandeer when initializing the stub. */
461
462 static struct hard_trap_info
463 {
464   unsigned char tt;             /* Trap type code for SPARClite */
465   unsigned char signo;          /* Signal that we map this trap into */
466 } hard_trap_info[] = {
467   {1, SIGSEGV},                 /* instruction access error */
468   {2, SIGILL},                  /* privileged instruction */
469   {3, SIGILL},                  /* illegal instruction */
470   {4, SIGEMT},                  /* fp disabled */
471   {36, SIGEMT},                 /* cp disabled */
472   {7, SIGBUS},                  /* mem address not aligned */
473   {9, SIGSEGV},                 /* data access exception */
474   {10, SIGEMT},                 /* tag overflow */
475   {128+1, SIGTRAP},             /* ta 1 - normal breakpoint instruction */
476   {0, 0}                        /* Must be last */
477 };
478
479 /* Set up exception handlers for tracing and breakpoints */
480
481 void
482 set_debug_traps()
483 {
484   struct hard_trap_info *ht;
485
486   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
487     exceptionHandler(ht->tt, trap_low);
488
489   /* In case GDB is started before us, ack any packets (presumably
490      "$?#xx") sitting there.  */
491
492   putDebugChar ('+');
493
494   initialized = 1;
495 }
496
497 asm ("
498 ! Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
499 ! assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
500 ! 0 would ever contain code that could mem fault.  This routine will skip
501 ! past the faulting instruction after setting mem_err.
502
503         .text
504         .align 4
505
506 _fltr_set_mem_err:
507         sethi %hi(_mem_err), %l0
508         st %l1, [%l0 + %lo(_mem_err)]
509         jmpl %l2, %g0
510         rett %l2+4
511 ");
512
513 static void
514 set_mem_fault_trap(enable)
515      int enable;
516 {
517   extern void fltr_set_mem_err();
518   mem_err = 0;
519
520   if (enable)
521     exceptionHandler(9, fltr_set_mem_err);
522   else
523     exceptionHandler(9, trap_low);
524 }
525
526 /* Convert the SPARC hardware trap type code to a unix signal number. */
527
528 static int
529 computeSignal(tt)
530      int tt;
531 {
532   struct hard_trap_info *ht;
533
534   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
535     if (ht->tt == tt)
536       return ht->signo;
537
538   return SIGHUP;                /* default for things we don't know about */
539 }
540
541 /*
542  * While we find nice hex chars, build an int.
543  * Return number of chars processed.
544  */
545
546 static int
547 hexToInt(char **ptr, int *intValue)
548 {
549   int numChars = 0;
550   int hexValue;
551
552   *intValue = 0;
553
554   while (**ptr)
555     {
556       hexValue = hex(**ptr);
557       if (hexValue < 0)
558         break;
559
560       *intValue = (*intValue << 4) | hexValue;
561       numChars ++;
562
563       (*ptr)++;
564     }
565
566   return (numChars);
567 }
568
569 /*
570  * This function does all command procesing for interfacing to gdb.  It
571  * returns 1 if you should skip the instruction at the trap address, 0
572  * otherwise.
573  */
574
575 extern void breakinst();
576
577 static void
578 handle_exception (registers)
579      unsigned long *registers;
580 {
581   int tt;                       /* Trap type */
582   int sigval;
583   int addr;
584   int length;
585   char *ptr;
586   unsigned long *sp;
587
588 /* First, we must force all of the windows to be spilled out */
589
590   asm(" 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         save %sp, -64, %sp
598         restore
599         restore
600         restore
601         restore
602         restore
603         restore
604         restore
605         restore
606 ");
607
608   if (registers[PC] == (unsigned long)breakinst)
609     {
610       registers[PC] = registers[NPC];
611       registers[NPC] += 4;
612     }
613
614   sp = (unsigned long *)registers[SP];
615
616   tt = (registers[TBR] >> 4) & 0xff;
617
618   /* reply to host that an exception has occurred */
619   sigval = computeSignal(tt);
620   ptr = remcomOutBuffer;
621
622   *ptr++ = 'T';
623   *ptr++ = hexchars[sigval >> 4];
624   *ptr++ = hexchars[sigval & 0xf];
625
626   *ptr++ = hexchars[PC >> 4];
627   *ptr++ = hexchars[PC & 0xf];
628   *ptr++ = ':';
629   ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
630   *ptr++ = ';';
631
632   *ptr++ = hexchars[FP >> 4];
633   *ptr++ = hexchars[FP & 0xf];
634   *ptr++ = ':';
635   ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
636   *ptr++ = ';';
637
638   *ptr++ = hexchars[SP >> 4];
639   *ptr++ = hexchars[SP & 0xf];
640   *ptr++ = ':';
641   ptr = mem2hex((char *)&sp, ptr, 4, 0);
642   *ptr++ = ';';
643
644   *ptr++ = hexchars[NPC >> 4];
645   *ptr++ = hexchars[NPC & 0xf];
646   *ptr++ = ':';
647   ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
648   *ptr++ = ';';
649
650   *ptr++ = hexchars[O7 >> 4];
651   *ptr++ = hexchars[O7 & 0xf];
652   *ptr++ = ':';
653   ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
654   *ptr++ = ';';
655
656   *ptr++ = 0;
657
658   putpacket(remcomOutBuffer);
659
660   while (1)
661     {
662       remcomOutBuffer[0] = 0;
663
664       getpacket(remcomInBuffer);
665       switch (remcomInBuffer[0])
666         {
667         case '?':
668           remcomOutBuffer[0] = 'S';
669           remcomOutBuffer[1] = hexchars[sigval >> 4];
670           remcomOutBuffer[2] = hexchars[sigval & 0xf];
671           remcomOutBuffer[3] = 0;
672           break;
673
674         case 'd':
675                                 /* toggle debug flag */
676           break;
677
678         case 'g':               /* return the value of the CPU registers */
679           {
680             ptr = remcomOutBuffer;
681             ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
682             ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
683             memset(ptr, '0', 32 * 8); /* Floating point */
684             mem2hex((char *)&registers[Y],
685                     ptr + 32 * 4 * 2,
686                     8 * 4,
687                     0);         /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
688           }
689           break;
690
691         case 'G':          /* set the value of the CPU registers - return OK */
692           {
693             unsigned long *newsp, psr;
694
695             psr = registers[PSR];
696
697             ptr = &remcomInBuffer[1];
698             hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
699             hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
700             hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y],
701                     8 * 4, 0);  /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
702
703             /* See if the stack pointer has moved.  If so, then copy the saved
704                locals and ins to the new location.  This keeps the window
705                overflow and underflow routines happy.  */
706
707             newsp = (unsigned long *)registers[SP];
708             if (sp != newsp)
709               sp = memcpy(newsp, sp, 16 * 4);
710
711             /* Don't allow CWP to be modified. */
712
713             if (psr != registers[PSR])
714               registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
715
716             strcpy(remcomOutBuffer,"OK");
717           }
718           break;
719
720         case 'm':         /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
721           /* Try to read %x,%x.  */
722
723           ptr = &remcomInBuffer[1];
724
725           if (hexToInt(&ptr, &addr)
726               && *ptr++ == ','
727               && hexToInt(&ptr, &length))
728             {
729               if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
730                 break;
731
732               strcpy (remcomOutBuffer, "E03");
733             }
734           else
735             strcpy(remcomOutBuffer,"E01");
736           break;
737
738         case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
739           /* Try to read '%x,%x:'.  */
740
741           ptr = &remcomInBuffer[1];
742
743           if (hexToInt(&ptr, &addr)
744               && *ptr++ == ','
745               && hexToInt(&ptr, &length)
746               && *ptr++ == ':')
747             {
748               if (hex2mem(ptr, (char *)addr, length, 1))
749                 strcpy(remcomOutBuffer, "OK");
750               else
751                 strcpy(remcomOutBuffer, "E03");
752             }
753           else
754             strcpy(remcomOutBuffer, "E02");
755           break;
756
757         case 'c':    /* cAA..AA    Continue at address AA..AA(optional) */
758           /* try to read optional parameter, pc unchanged if no parm */
759
760           ptr = &remcomInBuffer[1];
761           if (hexToInt(&ptr, &addr))
762             {
763               registers[PC] = addr;
764               registers[NPC] = addr + 4;
765             }
766
767 /* Need to flush the instruction cache here, as we may have deposited a
768    breakpoint, and the icache probably has no way of knowing that a data ref to
769    some location may have changed something that is in the instruction cache.
770  */
771
772           flush_i_cache();
773           return;
774
775           /* kill the program */
776         case 'k' :              /* do nothing */
777           break;
778 #if 0
779         case 't':               /* Test feature */
780           asm (" std %f30,[%sp]");
781           break;
782 #endif
783         case 'r':               /* Reset */
784           asm ("call 0
785                 nop ");
786           break;
787
788 #if 0
789 Disabled until we can unscrew this properly
790
791         case 'b':         /* bBB...  Set baud rate to BB... */
792           {
793             int baudrate;
794             extern void set_timer_3();
795
796             ptr = &remcomInBuffer[1];
797             if (!hexToInt(&ptr, &baudrate))
798               {
799                 strcpy(remcomOutBuffer,"B01");
800                 break;
801               }
802
803             /* Convert baud rate to uart clock divider */
804             switch (baudrate)
805               {
806               case 38400:
807                 baudrate = 16;
808                 break;
809               case 19200:
810                 baudrate = 33;
811                 break;
812               case 9600:
813                 baudrate = 65;
814                 break;
815               default:
816                 strcpy(remcomOutBuffer,"B02");
817                 goto x1;
818               }
819
820             putpacket("OK");    /* Ack before changing speed */
821             set_timer_3(baudrate); /* Set it */
822           }
823 x1:       break;
824 #endif
825         }                       /* switch */
826
827       /* reply to the request */
828       putpacket(remcomOutBuffer);
829     }
830 }
831
832 /* This function will generate a breakpoint exception.  It is used at the
833    beginning of a program to sync up with a debugger and can be used
834    otherwise as a quick means to stop program execution and "break" into
835    the debugger. */
836
837 void
838 breakpoint()
839 {
840   if (!initialized)
841     return;
842
843   asm(" .globl _breakinst
844
845         _breakinst: ta 1
846       ");
847 }