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