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