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