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