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