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