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