* Contribute CGEN simulator build support code.
[binutils-gdb.git] / gdb / sparcl-stub.c
blob3fcdc0ad7c1d3e156595bf4238ff6a2bb9b239bc
1 /****************************************************************************
3 THIS SOFTWARE IS NOT COPYRIGHTED
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.
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.
13 ****************************************************************************/
15 /****************************************************************************
16 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
18 * Module name: remcom.c $
19 * Revision: 1.34 $
20 * Date: 91/03/09 12:29:49 $
21 * Contributor: Lake Stevens Instrument Division$
23 * Description: low level support for gdb debugger. $
25 * Considerations: only works on target hardware $
27 * Written by: Glenn Engel $
28 * ModuleState: Experimental $
30 * NOTES: See Below $
32 * Modified for SPARC by Stu Grossman, Cygnus Support.
33 * Based on sparc-stub.c, it's modified for SPARClite Debug Unit hardware
34 * breakpoint support to create sparclite-stub.c, by Kung Hsu, Cygnus Support.
36 * This code has been extensively tested on the Fujitsu SPARClite demo board.
38 * To enable debugger support, two things need to happen. One, a
39 * call to set_debug_traps() is necessary in order to allow any breakpoints
40 * or error conditions to be properly intercepted and reported to gdb.
41 * Two, a breakpoint needs to be generated to begin communication. This
42 * is most easily accomplished by a call to breakpoint(). Breakpoint()
43 * simulates a breakpoint by executing a trap #1.
45 *************
47 * The following gdb commands are supported:
49 * command function Return value
51 * g return the value of the CPU registers hex data or ENN
52 * G set the value of the CPU registers OK or ENN
53 * P set the value of a single CPU register OK or ENN
55 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
56 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
58 * c Resume at current address SNN ( signal NN)
59 * cAA..AA Continue at address AA..AA SNN
61 * s Step one instruction SNN
62 * sAA..AA Step one instruction from AA..AA SNN
64 * k kill
66 * ? What was the last sigval ? SNN (signal NN)
68 * All commands and responses are sent with a packet which includes a
69 * checksum. A packet consists of
71 * $<packet info>#<checksum>.
73 * where
74 * <packet info> :: <characters representing the command or response>
75 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
77 * When a packet is received, it is first acknowledged with either '+' or '-'.
78 * '+' indicates a successful transfer. '-' indicates a failed transfer.
80 * Example:
82 * Host: Reply:
83 * $m0,10#2a +$00010203040506070809101112131415#42
85 ****************************************************************************/
87 #include <string.h>
88 #include <signal.h>
89 #include <sparclite.h>
91 /************************************************************************
93 * external low-level support routines
96 extern void putDebugChar (int c); /* write a single character */
97 extern int getDebugChar (void); /* read and return a single char */
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
104 static int initialized = 0; /* !0 means we've been initialized */
106 extern void breakinst ();
107 static void set_mem_fault_trap (int enable);
108 static void get_in_break_mode (void);
110 static const char hexchars[]="0123456789abcdef";
112 #define NUMREGS 80
114 /* Number of bytes of registers. */
115 #define NUMREGBYTES (NUMREGS * 4)
116 enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
117 O0, O1, O2, O3, O4, O5, SP, O7,
118 L0, L1, L2, L3, L4, L5, L6, L7,
119 I0, I1, I2, I3, I4, I5, FP, I7,
121 F0, F1, F2, F3, F4, F5, F6, F7,
122 F8, F9, F10, F11, F12, F13, F14, F15,
123 F16, F17, F18, F19, F20, F21, F22, F23,
124 F24, F25, F26, F27, F28, F29, F30, F31,
125 Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR,
126 DIA1, DIA2, DDA1, DDA2, DDV1, DDV2, DCR, DSR };
128 /*************************** ASSEMBLY CODE MACROS *************************/
129 /* */
131 extern void trap_low();
133 /* Create private copies of common functions used by the stub. This prevents
134 nasty interactions between app code and the stub (for instance if user steps
135 into strlen, etc..) */
137 static char *
138 strcpy (char *dst, const char *src)
140 char *retval = dst;
142 while ((*dst++ = *src++) != '\000');
144 return retval;
147 static void *
148 memcpy (void *vdst, const void *vsrc, int n)
150 char *dst = vdst;
151 const char *src = vsrc;
152 char *retval = dst;
154 while (n-- > 0)
155 *dst++ = *src++;
157 return retval;
160 asm("
161 .reserve trapstack, 1000 * 4, \"bss\", 8
163 .data
164 .align 4
166 in_trap_handler:
167 .word 0
169 .text
170 .align 4
172 ! This function is called when any SPARC trap (except window overflow or
173 ! underflow) occurs. It makes sure that the invalid register window is still
174 ! available before jumping into C code. It will also restore the world if you
175 ! return from handle_exception.
177 ! On entry, trap_low expects l1 and l2 to contain pc and npc respectivly.
178 ! Register usage throughout the routine is as follows:
180 ! l0 - psr
181 ! l1 - pc
182 ! l2 - npc
183 ! l3 - wim
184 ! l4 - scratch and y reg
185 ! l5 - scratch and tbr
186 ! l6 - unused
187 ! l7 - unused
189 .globl _trap_low
190 _trap_low:
191 mov %psr, %l0
192 mov %wim, %l3
194 srl %l3, %l0, %l4 ! wim >> cwp
195 cmp %l4, 1
196 bne window_fine ! Branch if not in the invalid window
199 ! Handle window overflow
201 mov %g1, %l4 ! Save g1, we use it to hold the wim
202 srl %l3, 1, %g1 ! Rotate wim right
203 tst %g1
204 bg good_wim ! Branch if new wim is non-zero
207 ! At this point, we need to bring a 1 into the high order bit of the wim.
208 ! Since we don't want to make any assumptions about the number of register
209 ! windows, we figure it out dynamically so as to setup the wim correctly.
211 not %g1 ! Fill g1 with ones
212 mov %g1, %wim ! Fill the wim with ones
216 mov %wim, %g1 ! Read back the wim
217 inc %g1 ! Now g1 has 1 just to left of wim
218 srl %g1, 1, %g1 ! Now put 1 at top of wim
219 mov %g0, %wim ! Clear wim so that subsequent save
220 nop ! won't trap
224 good_wim:
225 save %g0, %g0, %g0 ! Slip into next window
226 mov %g1, %wim ! Install the new wim
228 std %l0, [%sp + 0 * 4] ! save L & I registers
229 std %l2, [%sp + 2 * 4]
230 std %l4, [%sp + 4 * 4]
231 std %l6, [%sp + 6 * 4]
233 std %i0, [%sp + 8 * 4]
234 std %i2, [%sp + 10 * 4]
235 std %i4, [%sp + 12 * 4]
236 std %i6, [%sp + 14 * 4]
238 restore ! Go back to trap window.
239 mov %l4, %g1 ! Restore %g1
241 window_fine:
242 sethi %hi(in_trap_handler), %l4
243 ld [%lo(in_trap_handler) + %l4], %l5
244 tst %l5
245 bg recursive_trap
246 inc %l5
248 set trapstack+1000*4, %sp ! Switch to trap stack
250 recursive_trap:
251 st %l5, [%lo(in_trap_handler) + %l4]
252 sub %sp,(16+1+6+1+80)*4,%sp ! Make room for input & locals
253 ! + hidden arg + arg spill
254 ! + doubleword alignment
255 ! + registers[72] local var
257 std %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
258 std %g2, [%sp + (24 + 2) * 4]
259 std %g4, [%sp + (24 + 4) * 4]
260 std %g6, [%sp + (24 + 6) * 4]
262 std %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
263 std %i2, [%sp + (24 + 10) * 4]
264 std %i4, [%sp + (24 + 12) * 4]
265 std %i6, [%sp + (24 + 14) * 4]
267 mov %y, %l4
268 mov %tbr, %l5
269 st %l4, [%sp + (24 + 64) * 4] ! Y
270 st %l0, [%sp + (24 + 65) * 4] ! PSR
271 st %l3, [%sp + (24 + 66) * 4] ! WIM
272 st %l5, [%sp + (24 + 67) * 4] ! TBR
273 st %l1, [%sp + (24 + 68) * 4] ! PC
274 st %l2, [%sp + (24 + 69) * 4] ! NPC
276 or %l0, 0xf20, %l4
277 mov %l4, %psr ! Turn on traps, disable interrupts
279 set 0x1000, %l1
280 btst %l1, %l0 ! FP enabled?
281 be no_fpstore
284 ! Must save fsr first, to flush the FQ. This may cause a deferred fp trap, so
285 ! traps must be enabled to allow the trap handler to clean things up.
287 st %fsr, [%sp + (24 + 70) * 4]
289 std %f0, [%sp + (24 + 32) * 4]
290 std %f2, [%sp + (24 + 34) * 4]
291 std %f4, [%sp + (24 + 36) * 4]
292 std %f6, [%sp + (24 + 38) * 4]
293 std %f8, [%sp + (24 + 40) * 4]
294 std %f10, [%sp + (24 + 42) * 4]
295 std %f12, [%sp + (24 + 44) * 4]
296 std %f14, [%sp + (24 + 46) * 4]
297 std %f16, [%sp + (24 + 48) * 4]
298 std %f18, [%sp + (24 + 50) * 4]
299 std %f20, [%sp + (24 + 52) * 4]
300 std %f22, [%sp + (24 + 54) * 4]
301 std %f24, [%sp + (24 + 56) * 4]
302 std %f26, [%sp + (24 + 58) * 4]
303 std %f28, [%sp + (24 + 60) * 4]
304 std %f30, [%sp + (24 + 62) * 4]
305 no_fpstore:
307 call _handle_exception
308 add %sp, 24 * 4, %o0 ! Pass address of registers
310 ! Reload all of the registers that aren't on the stack
312 ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
313 ldd [%sp + (24 + 2) * 4], %g2
314 ldd [%sp + (24 + 4) * 4], %g4
315 ldd [%sp + (24 + 6) * 4], %g6
317 ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
318 ldd [%sp + (24 + 10) * 4], %i2
319 ldd [%sp + (24 + 12) * 4], %i4
320 ldd [%sp + (24 + 14) * 4], %i6
323 ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
324 ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
326 set 0x1000, %l5
327 btst %l5, %l1 ! FP enabled?
328 be no_fpreload
331 ldd [%sp + (24 + 32) * 4], %f0
332 ldd [%sp + (24 + 34) * 4], %f2
333 ldd [%sp + (24 + 36) * 4], %f4
334 ldd [%sp + (24 + 38) * 4], %f6
335 ldd [%sp + (24 + 40) * 4], %f8
336 ldd [%sp + (24 + 42) * 4], %f10
337 ldd [%sp + (24 + 44) * 4], %f12
338 ldd [%sp + (24 + 46) * 4], %f14
339 ldd [%sp + (24 + 48) * 4], %f16
340 ldd [%sp + (24 + 50) * 4], %f18
341 ldd [%sp + (24 + 52) * 4], %f20
342 ldd [%sp + (24 + 54) * 4], %f22
343 ldd [%sp + (24 + 56) * 4], %f24
344 ldd [%sp + (24 + 58) * 4], %f26
345 ldd [%sp + (24 + 60) * 4], %f28
346 ldd [%sp + (24 + 62) * 4], %f30
348 ld [%sp + (24 + 70) * 4], %fsr
349 no_fpreload:
351 restore ! Ensure that previous window is valid
352 save %g0, %g0, %g0 ! by causing a window_underflow trap
354 mov %l0, %y
355 mov %l1, %psr ! Make sure that traps are disabled
356 ! for rett
357 sethi %hi(in_trap_handler), %l4
358 ld [%lo(in_trap_handler) + %l4], %l5
359 dec %l5
360 st %l5, [%lo(in_trap_handler) + %l4]
362 jmpl %l2, %g0 ! Restore old PC
363 rett %l3 ! Restore old nPC
366 /* Convert ch from a hex digit to an int */
368 static int
369 hex (unsigned char ch)
371 if (ch >= 'a' && ch <= 'f')
372 return ch-'a'+10;
373 if (ch >= '0' && ch <= '9')
374 return ch-'0';
375 if (ch >= 'A' && ch <= 'F')
376 return ch-'A'+10;
377 return -1;
380 static char remcomInBuffer[BUFMAX];
381 static char remcomOutBuffer[BUFMAX];
383 /* scan for the sequence $<data>#<checksum> */
385 unsigned char *
386 getpacket (void)
388 unsigned char *buffer = &remcomInBuffer[0];
389 unsigned char checksum;
390 unsigned char xmitcsum;
391 int count;
392 char ch;
394 while (1)
396 /* wait around for the start character, ignore all other characters */
397 while ((ch = getDebugChar ()) != '$')
400 retry:
401 checksum = 0;
402 xmitcsum = -1;
403 count = 0;
405 /* now, read until a # or end of buffer is found */
406 while (count < BUFMAX)
408 ch = getDebugChar ();
409 if (ch == '$')
410 goto retry;
411 if (ch == '#')
412 break;
413 checksum = checksum + ch;
414 buffer[count] = ch;
415 count = count + 1;
417 buffer[count] = 0;
419 if (ch == '#')
421 ch = getDebugChar ();
422 xmitcsum = hex (ch) << 4;
423 ch = getDebugChar ();
424 xmitcsum += hex (ch);
426 if (checksum != xmitcsum)
428 putDebugChar ('-'); /* failed checksum */
430 else
432 putDebugChar ('+'); /* successful transfer */
434 /* if a sequence char is present, reply the sequence ID */
435 if (buffer[2] == ':')
437 putDebugChar (buffer[0]);
438 putDebugChar (buffer[1]);
440 return &buffer[3];
443 return &buffer[0];
449 /* send the packet in buffer. */
451 static void
452 putpacket (unsigned char *buffer)
454 unsigned char checksum;
455 int count;
456 unsigned char ch;
458 /* $<packet info>#<checksum>. */
461 putDebugChar('$');
462 checksum = 0;
463 count = 0;
465 while (ch = buffer[count])
467 putDebugChar (ch);
468 checksum += ch;
469 count += 1;
472 putDebugChar('#');
473 putDebugChar(hexchars[checksum >> 4]);
474 putDebugChar(hexchars[checksum & 0xf]);
477 while (getDebugChar() != '+');
480 /* Indicate to caller of mem2hex or hex2mem that there has been an
481 error. */
482 static volatile int mem_err = 0;
484 /* Convert the memory pointed to by mem into hex, placing result in buf.
485 * Return a pointer to the last char put in buf (null), in case of mem fault,
486 * return 0.
487 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
488 * a 0, else treat a fault like any other fault in the stub.
491 static unsigned char *
492 mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault)
494 unsigned char ch;
496 set_mem_fault_trap(may_fault);
498 while (count-- > 0)
500 ch = *mem++;
501 if (mem_err)
502 return 0;
503 *buf++ = hexchars[ch >> 4];
504 *buf++ = hexchars[ch & 0xf];
507 *buf = 0;
509 set_mem_fault_trap(0);
511 return buf;
514 /* convert the hex array pointed to by buf into binary to be placed in mem
515 * return a pointer to the character AFTER the last byte written */
517 static char *
518 hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
520 int i;
521 unsigned char ch;
523 set_mem_fault_trap(may_fault);
525 for (i=0; i<count; i++)
527 ch = hex(*buf++) << 4;
528 ch |= hex(*buf++);
529 *mem++ = ch;
530 if (mem_err)
531 return 0;
534 set_mem_fault_trap(0);
536 return mem;
539 /* This table contains the mapping between SPARC hardware trap types, and
540 signals, which are primarily what GDB understands. It also indicates
541 which hardware traps we need to commandeer when initializing the stub. */
543 static struct hard_trap_info
545 unsigned char tt; /* Trap type code for SPARClite */
546 unsigned char signo; /* Signal that we map this trap into */
547 } hard_trap_info[] = {
548 {0x01, SIGSEGV}, /* instruction access error */
549 {0x02, SIGILL}, /* privileged instruction */
550 {0x03, SIGILL}, /* illegal instruction */
551 {0x04, SIGEMT}, /* fp disabled */
552 {0x07, SIGBUS}, /* mem address not aligned */
553 {0x09, SIGSEGV}, /* data access exception */
554 {0x0a, SIGEMT}, /* tag overflow */
555 {0x20, SIGBUS}, /* r register access error */
556 {0x21, SIGBUS}, /* instruction access error */
557 {0x24, SIGEMT}, /* cp disabled */
558 {0x29, SIGBUS}, /* data access error */
559 {0x2a, SIGFPE}, /* divide by zero */
560 {0x2b, SIGBUS}, /* data store error */
561 {0x80+1, SIGTRAP}, /* ta 1 - normal breakpoint instruction */
562 {0xff, SIGTRAP}, /* hardware breakpoint */
563 {0, 0} /* Must be last */
566 /* Set up exception handlers for tracing and breakpoints */
568 void
569 set_debug_traps (void)
571 struct hard_trap_info *ht;
573 /* Only setup fp traps if the FP is disabled. */
575 for (ht = hard_trap_info;
576 ht->tt != 0 && ht->signo != 0;
577 ht++)
578 if (ht->tt != 4 || ! (read_psr () & 0x1000))
579 exceptionHandler(ht->tt, trap_low);
581 initialized = 1;
584 asm ("
585 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
586 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
587 ! 0 would ever contain code that could mem fault. This routine will skip
588 ! past the faulting instruction after setting mem_err.
590 .text
591 .align 4
593 _fltr_set_mem_err:
594 sethi %hi(_mem_err), %l0
595 st %l1, [%l0 + %lo(_mem_err)]
596 jmpl %l2, %g0
597 rett %l2+4
600 static void
601 set_mem_fault_trap (int enable)
603 extern void fltr_set_mem_err();
604 mem_err = 0;
606 if (enable)
607 exceptionHandler(9, fltr_set_mem_err);
608 else
609 exceptionHandler(9, trap_low);
612 asm ("
613 .text
614 .align 4
616 _dummy_hw_breakpoint:
617 jmpl %l2, %g0
618 rett %l2+4
623 static void
624 get_in_break_mode (void)
626 extern void dummy_hw_breakpoint();
628 exceptionHandler (255, dummy_hw_breakpoint);
630 asm ("ta 255");
632 exceptionHandler (255, trap_low);
635 /* Convert the SPARC hardware trap type code to a unix signal number. */
637 static int
638 computeSignal (int tt)
640 struct hard_trap_info *ht;
642 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
643 if (ht->tt == tt)
644 return ht->signo;
646 return SIGHUP; /* default for things we don't know about */
650 * While we find nice hex chars, build an int.
651 * Return number of chars processed.
654 static int
655 hexToInt(char **ptr, int *intValue)
657 int numChars = 0;
658 int hexValue;
660 *intValue = 0;
662 while (**ptr)
664 hexValue = hex(**ptr);
665 if (hexValue < 0)
666 break;
668 *intValue = (*intValue << 4) | hexValue;
669 numChars ++;
671 (*ptr)++;
674 return (numChars);
678 * This function does all command procesing for interfacing to gdb. It
679 * returns 1 if you should skip the instruction at the trap address, 0
680 * otherwise.
683 static void
684 handle_exception (unsigned long *registers)
686 int tt; /* Trap type */
687 int sigval;
688 int addr;
689 int length;
690 char *ptr;
691 unsigned long *sp;
692 unsigned long dsr;
694 /* First, we must force all of the windows to be spilled out */
696 asm(" save %sp, -64, %sp
697 save %sp, -64, %sp
698 save %sp, -64, %sp
699 save %sp, -64, %sp
700 save %sp, -64, %sp
701 save %sp, -64, %sp
702 save %sp, -64, %sp
703 save %sp, -64, %sp
704 restore
705 restore
706 restore
707 restore
708 restore
709 restore
710 restore
711 restore
714 get_in_break_mode (); /* Enable DSU register writes */
716 registers[DIA1] = read_asi (1, 0xff00);
717 registers[DIA2] = read_asi (1, 0xff04);
718 registers[DDA1] = read_asi (1, 0xff08);
719 registers[DDA2] = read_asi (1, 0xff0c);
720 registers[DDV1] = read_asi (1, 0xff10);
721 registers[DDV2] = read_asi (1, 0xff14);
722 registers[DCR] = read_asi (1, 0xff18);
723 registers[DSR] = read_asi (1, 0xff1c);
725 if (registers[PC] == (unsigned long)breakinst)
727 registers[PC] = registers[NPC];
728 registers[NPC] += 4;
730 sp = (unsigned long *)registers[SP];
732 dsr = (unsigned long)registers[DSR];
733 if (dsr & 0x3c)
734 tt = 255;
735 else
736 tt = (registers[TBR] >> 4) & 0xff;
738 /* reply to host that an exception has occurred */
739 sigval = computeSignal(tt);
740 ptr = remcomOutBuffer;
742 *ptr++ = 'T';
743 *ptr++ = hexchars[sigval >> 4];
744 *ptr++ = hexchars[sigval & 0xf];
746 *ptr++ = hexchars[PC >> 4];
747 *ptr++ = hexchars[PC & 0xf];
748 *ptr++ = ':';
749 ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
750 *ptr++ = ';';
752 *ptr++ = hexchars[FP >> 4];
753 *ptr++ = hexchars[FP & 0xf];
754 *ptr++ = ':';
755 ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
756 *ptr++ = ';';
758 *ptr++ = hexchars[SP >> 4];
759 *ptr++ = hexchars[SP & 0xf];
760 *ptr++ = ':';
761 ptr = mem2hex((char *)&sp, ptr, 4, 0);
762 *ptr++ = ';';
764 *ptr++ = hexchars[NPC >> 4];
765 *ptr++ = hexchars[NPC & 0xf];
766 *ptr++ = ':';
767 ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
768 *ptr++ = ';';
770 *ptr++ = hexchars[O7 >> 4];
771 *ptr++ = hexchars[O7 & 0xf];
772 *ptr++ = ':';
773 ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
774 *ptr++ = ';';
776 *ptr++ = 0;
778 putpacket(remcomOutBuffer);
780 while (1)
782 remcomOutBuffer[0] = 0;
784 ptr = getpacket();
785 switch (*ptr++)
787 case '?':
788 remcomOutBuffer[0] = 'S';
789 remcomOutBuffer[1] = hexchars[sigval >> 4];
790 remcomOutBuffer[2] = hexchars[sigval & 0xf];
791 remcomOutBuffer[3] = 0;
792 break;
794 case 'd':
795 /* toggle debug flag */
796 break;
798 case 'g': /* return the value of the CPU registers */
799 memcpy (&registers[L0], sp, 16 * 4); /* Copy L & I regs from stack */
800 mem2hex ((char *)registers, remcomOutBuffer, NUMREGBYTES, 0);
801 break;
803 case 'G': /* Set the value of all registers */
804 case 'P': /* Set the value of one register */
806 unsigned long *newsp, psr;
808 psr = registers[PSR];
810 if (ptr[-1] == 'P')
812 int regno;
814 if (hexToInt (&ptr, &regno)
815 && *ptr++ == '=')
816 if (regno >= L0 && regno <= I7)
817 hex2mem (ptr, sp + regno - L0, 4, 0);
818 else
819 hex2mem (ptr, (char *)&registers[regno], 4, 0);
820 else
822 strcpy (remcomOutBuffer, "E01");
823 break;
826 else
828 hex2mem (ptr, (char *)registers, NUMREGBYTES, 0);
829 memcpy (sp, &registers[L0], 16 * 4); /* Copy L & I regs to stack */
832 /* See if the stack pointer has moved. If so, then copy the saved
833 locals and ins to the new location. This keeps the window
834 overflow and underflow routines happy. */
836 newsp = (unsigned long *)registers[SP];
837 if (sp != newsp)
838 sp = memcpy(newsp, sp, 16 * 4);
840 /* Don't allow CWP to be modified. */
842 if (psr != registers[PSR])
843 registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
845 strcpy(remcomOutBuffer,"OK");
847 break;
849 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
850 /* Try to read %x,%x. */
852 if (hexToInt(&ptr, &addr)
853 && *ptr++ == ','
854 && hexToInt(&ptr, &length))
856 if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
857 break;
859 strcpy (remcomOutBuffer, "E03");
861 else
862 strcpy(remcomOutBuffer,"E01");
863 break;
865 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
866 /* Try to read '%x,%x:'. */
868 if (hexToInt(&ptr, &addr)
869 && *ptr++ == ','
870 && hexToInt(&ptr, &length)
871 && *ptr++ == ':')
873 if (hex2mem(ptr, (char *)addr, length, 1))
874 strcpy(remcomOutBuffer, "OK");
875 else
876 strcpy(remcomOutBuffer, "E03");
878 else
879 strcpy(remcomOutBuffer, "E02");
880 break;
882 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
883 /* try to read optional parameter, pc unchanged if no parm */
884 if (hexToInt(&ptr, &addr))
886 registers[PC] = addr;
887 registers[NPC] = addr + 4;
890 /* Need to flush the instruction cache here, as we may have deposited a
891 breakpoint, and the icache probably has no way of knowing that a data ref to
892 some location may have changed something that is in the instruction cache.
895 flush_i_cache ();
897 if (!(registers[DSR] & 0x1) /* DSU enabled? */
898 && !(registers[DCR] & 0x200)) /* Are we in break state? */
899 { /* Yes, set the DSU regs */
900 write_asi (1, 0xff00, registers[DIA1]);
901 write_asi (1, 0xff04, registers[DIA2]);
902 write_asi (1, 0xff08, registers[DDA1]);
903 write_asi (1, 0xff0c, registers[DDA2]);
904 write_asi (1, 0xff10, registers[DDV1]);
905 write_asi (1, 0xff14, registers[DDV2]);
906 write_asi (1, 0xff1c, registers[DSR]);
907 write_asi (1, 0xff18, registers[DCR] | 0x200); /* Clear break */
910 return;
912 /* kill the program */
913 case 'k' : /* do nothing */
914 break;
915 #if 0
916 case 't': /* Test feature */
917 asm (" std %f30,[%sp]");
918 break;
919 #endif
920 case 'r': /* Reset */
921 asm ("call 0
922 nop ");
923 break;
924 } /* switch */
926 /* reply to the request */
927 putpacket(remcomOutBuffer);
931 /* This function will generate a breakpoint exception. It is used at the
932 beginning of a program to sync up with a debugger and can be used
933 otherwise as a quick means to stop program execution and "break" into
934 the debugger. */
936 void
937 breakpoint (void)
939 if (!initialized)
940 return;
942 asm(" .globl _breakinst
944 _breakinst: ta 1