Protoization.
[external/binutils.git] / gdb / sparcl-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  *  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.
35  *
36  *  This code has been extensively tested on the Fujitsu SPARClite demo board.
37  *
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.
44  *
45  *************
46  *
47  *    The following gdb commands are supported:
48  *
49  * command          function                               Return value
50  *
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
54  *
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
57  *
58  *    c             Resume at current address              SNN   ( signal NN)
59  *    cAA..AA       Continue at address AA..AA             SNN
60  *
61  *    s             Step one instruction                   SNN
62  *    sAA..AA       Step one instruction from AA..AA       SNN
63  *
64  *    k             kill
65  *
66  *    ?             What was the last sigval ?             SNN   (signal NN)
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 <sparclite.h>
90
91 /************************************************************************
92  *
93  * external low-level support routines
94  */
95
96 extern void putDebugChar (int c); /* write a single character      */
97 extern int getDebugChar (void); /* 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 extern void breakinst ();
107 static void set_mem_fault_trap (int enable);
108 static void get_in_break_mode (void);
109
110 static const char hexchars[]="0123456789abcdef";
111
112 #define NUMREGS 80 
113
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,
120
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 };
127
128 /***************************  ASSEMBLY CODE MACROS *************************/
129 /*                                                                         */
130
131 extern void trap_low();
132
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..) */
136
137 static char *
138 strcpy (char *dst, const char *src)
139 {
140   char *retval = dst;
141
142   while ((*dst++ = *src++) != '\000');
143
144   return retval;
145 }
146
147 static void *
148 memcpy (void *vdst, const void *vsrc, int n)
149 {
150   char *dst = vdst;
151   const char *src = vsrc;
152   char *retval = dst;
153
154   while (n-- > 0)
155     *dst++ = *src++;
156
157   return retval;
158 }
159
160 asm("
161         .reserve trapstack, 1000 * 4, \"bss\", 8
162
163         .data
164         .align  4
165
166 in_trap_handler:
167         .word   0
168
169         .text
170         .align 4
171
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.
176 !
177 ! On entry, trap_low expects l1 and l2 to contain pc and npc respectivly.
178 ! Register usage throughout the routine is as follows:
179 !
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
188
189         .globl _trap_low
190 _trap_low:
191         mov     %psr, %l0
192         mov     %wim, %l3
193
194         srl     %l3, %l0, %l4           ! wim >> cwp
195         cmp     %l4, 1
196         bne     window_fine             ! Branch if not in the invalid window
197         nop
198
199 ! Handle window overflow
200
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
205         nop
206
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.
210
211         not     %g1                     ! Fill g1 with ones
212         mov     %g1, %wim               ! Fill the wim with ones
213         nop
214         nop
215         nop
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
221         nop
222         nop
223
224 good_wim:
225         save    %g0, %g0, %g0           ! Slip into next window
226         mov     %g1, %wim               ! Install the new wim
227
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]
232
233         std     %i0, [%sp + 8 * 4]
234         std     %i2, [%sp + 10 * 4]
235         std     %i4, [%sp + 12 * 4]
236         std     %i6, [%sp + 14 * 4]
237
238         restore                         ! Go back to trap window.
239         mov     %l4, %g1                ! Restore %g1
240
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
247
248         set     trapstack+1000*4, %sp   ! Switch to trap stack
249
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
256
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]
261
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]
266
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
275
276         or      %l0, 0xf20, %l4
277         mov     %l4, %psr               ! Turn on traps, disable interrupts
278
279         set     0x1000, %l1
280         btst    %l1, %l0                ! FP enabled?
281         be      no_fpstore
282         nop
283
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.
286
287         st      %fsr, [%sp + (24 + 70) * 4]
288
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:
306
307         call    _handle_exception
308         add     %sp, 24 * 4, %o0        ! Pass address of registers
309
310 ! Reload all of the registers that aren't on the stack
311
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
316
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
321
322
323         ldd     [%sp + (24 + 64) * 4], %l0 ! Y & PSR
324         ldd     [%sp + (24 + 68) * 4], %l2 ! PC & NPC
325
326         set     0x1000, %l5
327         btst    %l5, %l1                ! FP enabled?
328         be      no_fpreload
329         nop
330
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
347
348         ld      [%sp + (24 + 70) * 4], %fsr
349 no_fpreload:
350
351         restore                         ! Ensure that previous window is valid
352         save    %g0, %g0, %g0           !  by causing a window_underflow trap
353
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]
361
362         jmpl    %l2, %g0                ! Restore old PC
363         rett    %l3                     ! Restore old nPC
364 ");
365
366 /* Convert ch from a hex digit to an int */
367
368 static int
369 hex (unsigned char ch)
370 {
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;
378 }
379
380 static char remcomInBuffer[BUFMAX];
381 static char remcomOutBuffer[BUFMAX];
382
383 /* scan for the sequence $<data>#<checksum>     */
384
385 unsigned char *
386 getpacket (void)
387 {
388   unsigned char *buffer = &remcomInBuffer[0];
389   unsigned char checksum;
390   unsigned char xmitcsum;
391   int count;
392   char ch;
393
394   while (1)
395     {
396       /* wait around for the start character, ignore all other characters */
397       while ((ch = getDebugChar ()) != '$')
398         ;
399
400 retry:
401       checksum = 0;
402       xmitcsum = -1;
403       count = 0;
404
405       /* now, read until a # or end of buffer is found */
406       while (count < BUFMAX)
407         {
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;
416         }
417       buffer[count] = 0;
418
419       if (ch == '#')
420         {
421           ch = getDebugChar ();
422           xmitcsum = hex (ch) << 4;
423           ch = getDebugChar ();
424           xmitcsum += hex (ch);
425
426           if (checksum != xmitcsum)
427             {
428               putDebugChar ('-');       /* failed checksum */
429             }
430           else
431             {
432               putDebugChar ('+');       /* successful transfer */
433
434               /* if a sequence char is present, reply the sequence ID */
435               if (buffer[2] == ':')
436                 {
437                   putDebugChar (buffer[0]);
438                   putDebugChar (buffer[1]);
439
440                   return &buffer[3];
441                 }
442
443               return &buffer[0];
444             }
445         }
446     }
447 }
448
449 /* send the packet in buffer.  */
450
451 static void
452 putpacket (unsigned char *buffer)
453 {
454   unsigned char checksum;
455   int count;
456   unsigned char ch;
457
458   /*  $<packet info>#<checksum>. */
459   do
460     {
461       putDebugChar('$');
462       checksum = 0;
463       count = 0;
464
465       while (ch = buffer[count])
466         {
467           putDebugChar (ch);
468           checksum += ch;
469           count += 1;
470         }
471
472       putDebugChar('#');
473       putDebugChar(hexchars[checksum >> 4]);
474       putDebugChar(hexchars[checksum & 0xf]);
475
476     }
477   while (getDebugChar() != '+');
478 }
479
480 /* Indicate to caller of mem2hex or hex2mem that there has been an
481    error.  */
482 static volatile int mem_err = 0;
483
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.
489  */
490
491 static unsigned char *
492 mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault)
493 {
494   unsigned char ch;
495
496   set_mem_fault_trap(may_fault);
497
498   while (count-- > 0)
499     {
500       ch = *mem++;
501       if (mem_err)
502         return 0;
503       *buf++ = hexchars[ch >> 4];
504       *buf++ = hexchars[ch & 0xf];
505     }
506
507   *buf = 0;
508
509   set_mem_fault_trap(0);
510
511   return buf;
512 }
513
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 */
516
517 static char *
518 hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
519 {
520   int i;
521   unsigned char ch;
522
523   set_mem_fault_trap(may_fault);
524
525   for (i=0; i<count; i++)
526     {
527       ch = hex(*buf++) << 4;
528       ch |= hex(*buf++);
529       *mem++ = ch;
530       if (mem_err)
531         return 0;
532     }
533
534   set_mem_fault_trap(0);
535
536   return mem;
537 }
538
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. */
542
543 static struct hard_trap_info
544 {
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 */
564 };
565
566 /* Set up exception handlers for tracing and breakpoints */
567
568 void
569 set_debug_traps (void)
570 {
571   struct hard_trap_info *ht;
572
573 /* Only setup fp traps if the FP is disabled.  */
574
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);
580
581   initialized = 1;
582 }
583
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.
589
590         .text
591         .align 4
592
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
598 ");
599
600 static void
601 set_mem_fault_trap (int enable)
602 {
603   extern void fltr_set_mem_err();
604   mem_err = 0;
605
606   if (enable)
607     exceptionHandler(9, fltr_set_mem_err);
608   else
609     exceptionHandler(9, trap_low);
610 }
611
612 asm ("
613         .text
614         .align 4
615
616 _dummy_hw_breakpoint:
617         jmpl %l2, %g0
618         rett %l2+4
619         nop
620         nop
621 ");
622
623 static void
624 get_in_break_mode (void)
625 {
626   extern void dummy_hw_breakpoint();
627
628   exceptionHandler (255, dummy_hw_breakpoint);
629
630   asm ("ta 255");
631
632   exceptionHandler (255, trap_low);
633 }
634
635 /* Convert the SPARC hardware trap type code to a unix signal number. */
636
637 static int
638 computeSignal (int tt)
639 {
640   struct hard_trap_info *ht;
641
642   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
643     if (ht->tt == tt)
644       return ht->signo;
645
646   return SIGHUP;                /* default for things we don't know about */
647 }
648
649 /*
650  * While we find nice hex chars, build an int.
651  * Return number of chars processed.
652  */
653
654 static int
655 hexToInt(char **ptr, int *intValue)
656 {
657   int numChars = 0;
658   int hexValue;
659
660   *intValue = 0;
661
662   while (**ptr)
663     {
664       hexValue = hex(**ptr);
665       if (hexValue < 0)
666         break;
667
668       *intValue = (*intValue << 4) | hexValue;
669       numChars ++;
670
671       (*ptr)++;
672     }
673
674   return (numChars);
675 }
676
677 /*
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.
681  */
682
683 static void
684 handle_exception (unsigned long *registers)
685 {
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;
693
694 /* First, we must force all of the windows to be spilled out */
695
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
712 ");
713
714   get_in_break_mode ();         /* Enable DSU register writes */
715
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);
724
725   if (registers[PC] == (unsigned long)breakinst)
726     {
727       registers[PC] = registers[NPC];
728       registers[NPC] += 4;
729     }
730   sp = (unsigned long *)registers[SP];
731
732   dsr = (unsigned long)registers[DSR];
733   if (dsr & 0x3c)
734     tt = 255;
735   else
736     tt = (registers[TBR] >> 4) & 0xff;
737
738   /* reply to host that an exception has occurred */
739   sigval = computeSignal(tt);
740   ptr = remcomOutBuffer;
741
742   *ptr++ = 'T';
743   *ptr++ = hexchars[sigval >> 4];
744   *ptr++ = hexchars[sigval & 0xf];
745
746   *ptr++ = hexchars[PC >> 4];
747   *ptr++ = hexchars[PC & 0xf];
748   *ptr++ = ':';
749   ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
750   *ptr++ = ';';
751
752   *ptr++ = hexchars[FP >> 4];
753   *ptr++ = hexchars[FP & 0xf];
754   *ptr++ = ':';
755   ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
756   *ptr++ = ';';
757
758   *ptr++ = hexchars[SP >> 4];
759   *ptr++ = hexchars[SP & 0xf];
760   *ptr++ = ':';
761   ptr = mem2hex((char *)&sp, ptr, 4, 0);
762   *ptr++ = ';';
763
764   *ptr++ = hexchars[NPC >> 4];
765   *ptr++ = hexchars[NPC & 0xf];
766   *ptr++ = ':';
767   ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
768   *ptr++ = ';';
769
770   *ptr++ = hexchars[O7 >> 4];
771   *ptr++ = hexchars[O7 & 0xf];
772   *ptr++ = ':';
773   ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
774   *ptr++ = ';';
775
776   *ptr++ = 0;
777
778   putpacket(remcomOutBuffer);
779
780   while (1)
781     {
782       remcomOutBuffer[0] = 0;
783
784       ptr = getpacket();
785       switch (*ptr++)
786         {
787         case '?':
788           remcomOutBuffer[0] = 'S';
789           remcomOutBuffer[1] = hexchars[sigval >> 4];
790           remcomOutBuffer[2] = hexchars[sigval & 0xf];
791           remcomOutBuffer[3] = 0;
792           break;
793
794         case 'd':
795                                 /* toggle debug flag */
796           break;
797
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;
802
803         case 'G':               /* Set the value of all registers */
804         case 'P':               /* Set the value of one register */
805           {
806             unsigned long *newsp, psr;
807
808             psr = registers[PSR];
809
810             if (ptr[-1] == 'P')
811               {
812                 int regno;
813
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
821                   {
822                     strcpy (remcomOutBuffer, "E01");
823                     break;
824                   }
825               }
826             else
827               {
828                 hex2mem (ptr, (char *)registers, NUMREGBYTES, 0);
829                 memcpy (sp, &registers[L0], 16 * 4); /* Copy L & I regs to stack */
830               }
831
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.  */
835
836             newsp = (unsigned long *)registers[SP];
837             if (sp != newsp)
838               sp = memcpy(newsp, sp, 16 * 4);
839
840             /* Don't allow CWP to be modified. */
841
842             if (psr != registers[PSR])
843               registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
844
845             strcpy(remcomOutBuffer,"OK");
846           }
847           break;
848
849         case 'm':         /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
850           /* Try to read %x,%x.  */
851
852           if (hexToInt(&ptr, &addr)
853               && *ptr++ == ','
854               && hexToInt(&ptr, &length))
855             {
856               if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
857                 break;
858
859               strcpy (remcomOutBuffer, "E03");
860             }
861           else
862             strcpy(remcomOutBuffer,"E01");
863           break;
864
865         case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
866           /* Try to read '%x,%x:'.  */
867
868           if (hexToInt(&ptr, &addr)
869               && *ptr++ == ','
870               && hexToInt(&ptr, &length)
871               && *ptr++ == ':')
872             {
873               if (hex2mem(ptr, (char *)addr, length, 1))
874                 strcpy(remcomOutBuffer, "OK");
875               else
876                 strcpy(remcomOutBuffer, "E03");
877             }
878           else
879             strcpy(remcomOutBuffer, "E02");
880           break;
881
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))
885             {
886               registers[PC] = addr;
887               registers[NPC] = addr + 4;
888             }
889
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.
893  */
894
895           flush_i_cache ();
896
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 */
908             }
909
910           return;
911
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 */
925
926       /* reply to the request */
927       putpacket(remcomOutBuffer);
928     }
929 }
930
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. */
935
936 void
937 breakpoint (void)
938 {
939   if (!initialized)
940     return;
941
942   asm(" .globl _breakinst
943
944         _breakinst: ta 1
945       ");
946 }