This commit was generated by cvs2svn to track changes on a CVS vendor
[platform/upstream/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(ch)
370      unsigned char ch;
371 {
372   if (ch >= 'a' && ch <= 'f')
373     return ch-'a'+10;
374   if (ch >= '0' && ch <= '9')
375     return ch-'0';
376   if (ch >= 'A' && ch <= 'F')
377     return ch-'A'+10;
378   return -1;
379 }
380
381 static char remcomInBuffer[BUFMAX];
382 static char remcomOutBuffer[BUFMAX];
383
384 /* scan for the sequence $<data>#<checksum>     */
385
386 unsigned char *
387 getpacket ()
388 {
389   unsigned char *buffer = &remcomInBuffer[0];
390   unsigned char checksum;
391   unsigned char xmitcsum;
392   int count;
393   char ch;
394
395   while (1)
396     {
397       /* wait around for the start character, ignore all other characters */
398       while ((ch = getDebugChar ()) != '$')
399         ;
400
401 retry:
402       checksum = 0;
403       xmitcsum = -1;
404       count = 0;
405
406       /* now, read until a # or end of buffer is found */
407       while (count < BUFMAX)
408         {
409           ch = getDebugChar ();
410           if (ch == '$')
411             goto retry;
412           if (ch == '#')
413             break;
414           checksum = checksum + ch;
415           buffer[count] = ch;
416           count = count + 1;
417         }
418       buffer[count] = 0;
419
420       if (ch == '#')
421         {
422           ch = getDebugChar ();
423           xmitcsum = hex (ch) << 4;
424           ch = getDebugChar ();
425           xmitcsum += hex (ch);
426
427           if (checksum != xmitcsum)
428             {
429               putDebugChar ('-');       /* failed checksum */
430             }
431           else
432             {
433               putDebugChar ('+');       /* successful transfer */
434
435               /* if a sequence char is present, reply the sequence ID */
436               if (buffer[2] == ':')
437                 {
438                   putDebugChar (buffer[0]);
439                   putDebugChar (buffer[1]);
440
441                   return &buffer[3];
442                 }
443
444               return &buffer[0];
445             }
446         }
447     }
448 }
449
450 /* send the packet in buffer.  */
451
452 static void
453 putpacket(buffer)
454      unsigned char *buffer;
455 {
456   unsigned char checksum;
457   int count;
458   unsigned char ch;
459
460   /*  $<packet info>#<checksum>. */
461   do
462     {
463       putDebugChar('$');
464       checksum = 0;
465       count = 0;
466
467       while (ch = buffer[count])
468         {
469           putDebugChar (ch);
470           checksum += ch;
471           count += 1;
472         }
473
474       putDebugChar('#');
475       putDebugChar(hexchars[checksum >> 4]);
476       putDebugChar(hexchars[checksum & 0xf]);
477
478     }
479   while (getDebugChar() != '+');
480 }
481
482 /* Indicate to caller of mem2hex or hex2mem that there has been an
483    error.  */
484 static volatile int mem_err = 0;
485
486 /* Convert the memory pointed to by mem into hex, placing result in buf.
487  * Return a pointer to the last char put in buf (null), in case of mem fault,
488  * return 0.
489  * If MAY_FAULT is non-zero, then we will handle memory faults by returning
490  * a 0, else treat a fault like any other fault in the stub.
491  */
492
493 static unsigned char *
494 mem2hex(mem, buf, count, may_fault)
495      unsigned char *mem;
496      unsigned char *buf;
497      int count;
498      int may_fault;
499 {
500   unsigned char ch;
501
502   set_mem_fault_trap(may_fault);
503
504   while (count-- > 0)
505     {
506       ch = *mem++;
507       if (mem_err)
508         return 0;
509       *buf++ = hexchars[ch >> 4];
510       *buf++ = hexchars[ch & 0xf];
511     }
512
513   *buf = 0;
514
515   set_mem_fault_trap(0);
516
517   return buf;
518 }
519
520 /* convert the hex array pointed to by buf into binary to be placed in mem
521  * return a pointer to the character AFTER the last byte written */
522
523 static char *
524 hex2mem(buf, mem, count, may_fault)
525      unsigned char *buf;
526      unsigned char *mem;
527      int count;
528      int may_fault;
529 {
530   int i;
531   unsigned char ch;
532
533   set_mem_fault_trap(may_fault);
534
535   for (i=0; i<count; i++)
536     {
537       ch = hex(*buf++) << 4;
538       ch |= hex(*buf++);
539       *mem++ = ch;
540       if (mem_err)
541         return 0;
542     }
543
544   set_mem_fault_trap(0);
545
546   return mem;
547 }
548
549 /* This table contains the mapping between SPARC hardware trap types, and
550    signals, which are primarily what GDB understands.  It also indicates
551    which hardware traps we need to commandeer when initializing the stub. */
552
553 static struct hard_trap_info
554 {
555   unsigned char tt;             /* Trap type code for SPARClite */
556   unsigned char signo;          /* Signal that we map this trap into */
557 } hard_trap_info[] = {
558   {0x01, SIGSEGV},              /* instruction access error */
559   {0x02, SIGILL},               /* privileged instruction */
560   {0x03, SIGILL},               /* illegal instruction */
561   {0x04, SIGEMT},               /* fp disabled */
562   {0x07, SIGBUS},               /* mem address not aligned */
563   {0x09, SIGSEGV},              /* data access exception */
564   {0x0a, SIGEMT},               /* tag overflow */
565   {0x20, SIGBUS},               /* r register access error */
566   {0x21, SIGBUS},               /* instruction access error */
567   {0x24, SIGEMT},               /* cp disabled */
568   {0x29, SIGBUS},               /* data access error */
569   {0x2a, SIGFPE},               /* divide by zero */
570   {0x2b, SIGBUS},               /* data store error */
571   {0x80+1, SIGTRAP},            /* ta 1 - normal breakpoint instruction */
572   {0xff, SIGTRAP},              /* hardware breakpoint */
573   {0, 0}                        /* Must be last */
574 };
575
576 /* Set up exception handlers for tracing and breakpoints */
577
578 void
579 set_debug_traps()
580 {
581   struct hard_trap_info *ht;
582
583 /* Only setup fp traps if the FP is disabled.  */
584
585   for (ht = hard_trap_info;
586        ht->tt != 0 && ht->signo != 0;
587        ht++)
588     if (ht->tt != 4 || ! (read_psr () & 0x1000))
589       exceptionHandler(ht->tt, trap_low);
590
591   initialized = 1;
592 }
593
594 asm ("
595 ! Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
596 ! assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
597 ! 0 would ever contain code that could mem fault.  This routine will skip
598 ! past the faulting instruction after setting mem_err.
599
600         .text
601         .align 4
602
603 _fltr_set_mem_err:
604         sethi %hi(_mem_err), %l0
605         st %l1, [%l0 + %lo(_mem_err)]
606         jmpl %l2, %g0
607         rett %l2+4
608 ");
609
610 static void
611 set_mem_fault_trap(enable)
612      int enable;
613 {
614   extern void fltr_set_mem_err();
615   mem_err = 0;
616
617   if (enable)
618     exceptionHandler(9, fltr_set_mem_err);
619   else
620     exceptionHandler(9, trap_low);
621 }
622
623 asm ("
624         .text
625         .align 4
626
627 _dummy_hw_breakpoint:
628         jmpl %l2, %g0
629         rett %l2+4
630         nop
631         nop
632 ");
633
634 static void
635 get_in_break_mode()
636 {
637   extern void dummy_hw_breakpoint();
638
639   exceptionHandler (255, dummy_hw_breakpoint);
640
641   asm ("ta 255");
642
643   exceptionHandler (255, trap_low);
644 }
645
646 /* Convert the SPARC hardware trap type code to a unix signal number. */
647
648 static int
649 computeSignal(tt)
650      int tt;
651 {
652   struct hard_trap_info *ht;
653
654   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
655     if (ht->tt == tt)
656       return ht->signo;
657
658   return SIGHUP;                /* default for things we don't know about */
659 }
660
661 /*
662  * While we find nice hex chars, build an int.
663  * Return number of chars processed.
664  */
665
666 static int
667 hexToInt(char **ptr, int *intValue)
668 {
669   int numChars = 0;
670   int hexValue;
671
672   *intValue = 0;
673
674   while (**ptr)
675     {
676       hexValue = hex(**ptr);
677       if (hexValue < 0)
678         break;
679
680       *intValue = (*intValue << 4) | hexValue;
681       numChars ++;
682
683       (*ptr)++;
684     }
685
686   return (numChars);
687 }
688
689 /*
690  * This function does all command procesing for interfacing to gdb.  It
691  * returns 1 if you should skip the instruction at the trap address, 0
692  * otherwise.
693  */
694
695 static void
696 handle_exception (registers)
697      unsigned long *registers;
698 {
699   int tt;                       /* Trap type */
700   int sigval;
701   int addr;
702   int length;
703   char *ptr;
704   unsigned long *sp;
705   unsigned long dsr;
706
707 /* First, we must force all of the windows to be spilled out */
708
709   asm(" save %sp, -64, %sp
710         save %sp, -64, %sp
711         save %sp, -64, %sp
712         save %sp, -64, %sp
713         save %sp, -64, %sp
714         save %sp, -64, %sp
715         save %sp, -64, %sp
716         save %sp, -64, %sp
717         restore
718         restore
719         restore
720         restore
721         restore
722         restore
723         restore
724         restore
725 ");
726
727   get_in_break_mode ();         /* Enable DSU register writes */
728
729   registers[DIA1] = read_asi (1, 0xff00);
730   registers[DIA2] = read_asi (1, 0xff04);
731   registers[DDA1] = read_asi (1, 0xff08);
732   registers[DDA2] = read_asi (1, 0xff0c);
733   registers[DDV1] = read_asi (1, 0xff10);
734   registers[DDV2] = read_asi (1, 0xff14);
735   registers[DCR] = read_asi (1, 0xff18);
736   registers[DSR] = read_asi (1, 0xff1c);
737
738   if (registers[PC] == (unsigned long)breakinst)
739     {
740       registers[PC] = registers[NPC];
741       registers[NPC] += 4;
742     }
743   sp = (unsigned long *)registers[SP];
744
745   dsr = (unsigned long)registers[DSR];
746   if (dsr & 0x3c)
747     tt = 255;
748   else
749     tt = (registers[TBR] >> 4) & 0xff;
750
751   /* reply to host that an exception has occurred */
752   sigval = computeSignal(tt);
753   ptr = remcomOutBuffer;
754
755   *ptr++ = 'T';
756   *ptr++ = hexchars[sigval >> 4];
757   *ptr++ = hexchars[sigval & 0xf];
758
759   *ptr++ = hexchars[PC >> 4];
760   *ptr++ = hexchars[PC & 0xf];
761   *ptr++ = ':';
762   ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
763   *ptr++ = ';';
764
765   *ptr++ = hexchars[FP >> 4];
766   *ptr++ = hexchars[FP & 0xf];
767   *ptr++ = ':';
768   ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
769   *ptr++ = ';';
770
771   *ptr++ = hexchars[SP >> 4];
772   *ptr++ = hexchars[SP & 0xf];
773   *ptr++ = ':';
774   ptr = mem2hex((char *)&sp, ptr, 4, 0);
775   *ptr++ = ';';
776
777   *ptr++ = hexchars[NPC >> 4];
778   *ptr++ = hexchars[NPC & 0xf];
779   *ptr++ = ':';
780   ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
781   *ptr++ = ';';
782
783   *ptr++ = hexchars[O7 >> 4];
784   *ptr++ = hexchars[O7 & 0xf];
785   *ptr++ = ':';
786   ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
787   *ptr++ = ';';
788
789   *ptr++ = 0;
790
791   putpacket(remcomOutBuffer);
792
793   while (1)
794     {
795       remcomOutBuffer[0] = 0;
796
797       ptr = getpacket();
798       switch (*ptr++)
799         {
800         case '?':
801           remcomOutBuffer[0] = 'S';
802           remcomOutBuffer[1] = hexchars[sigval >> 4];
803           remcomOutBuffer[2] = hexchars[sigval & 0xf];
804           remcomOutBuffer[3] = 0;
805           break;
806
807         case 'd':
808                                 /* toggle debug flag */
809           break;
810
811         case 'g':               /* return the value of the CPU registers */
812           memcpy (&registers[L0], sp, 16 * 4); /* Copy L & I regs from stack */
813           mem2hex ((char *)registers, remcomOutBuffer, NUMREGBYTES, 0);
814           break;
815
816         case 'G':               /* Set the value of all registers */
817         case 'P':               /* Set the value of one register */
818           {
819             unsigned long *newsp, psr;
820
821             psr = registers[PSR];
822
823             if (ptr[-1] == 'P')
824               {
825                 int regno;
826
827                 if (hexToInt (&ptr, &regno)
828                     && *ptr++ == '=')
829                   if (regno >= L0 && regno <= I7)
830                     hex2mem (ptr, sp + regno - L0, 4, 0);
831                   else
832                     hex2mem (ptr, (char *)&registers[regno], 4, 0);
833                 else
834                   {
835                     strcpy (remcomOutBuffer, "E01");
836                     break;
837                   }
838               }
839             else
840               {
841                 hex2mem (ptr, (char *)registers, NUMREGBYTES, 0);
842                 memcpy (sp, &registers[L0], 16 * 4); /* Copy L & I regs to stack */
843               }
844
845             /* See if the stack pointer has moved.  If so, then copy the saved
846                locals and ins to the new location.  This keeps the window
847                overflow and underflow routines happy.  */
848
849             newsp = (unsigned long *)registers[SP];
850             if (sp != newsp)
851               sp = memcpy(newsp, sp, 16 * 4);
852
853             /* Don't allow CWP to be modified. */
854
855             if (psr != registers[PSR])
856               registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
857
858             strcpy(remcomOutBuffer,"OK");
859           }
860           break;
861
862         case 'm':         /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
863           /* Try to read %x,%x.  */
864
865           if (hexToInt(&ptr, &addr)
866               && *ptr++ == ','
867               && hexToInt(&ptr, &length))
868             {
869               if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
870                 break;
871
872               strcpy (remcomOutBuffer, "E03");
873             }
874           else
875             strcpy(remcomOutBuffer,"E01");
876           break;
877
878         case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
879           /* Try to read '%x,%x:'.  */
880
881           if (hexToInt(&ptr, &addr)
882               && *ptr++ == ','
883               && hexToInt(&ptr, &length)
884               && *ptr++ == ':')
885             {
886               if (hex2mem(ptr, (char *)addr, length, 1))
887                 strcpy(remcomOutBuffer, "OK");
888               else
889                 strcpy(remcomOutBuffer, "E03");
890             }
891           else
892             strcpy(remcomOutBuffer, "E02");
893           break;
894
895         case 'c':    /* cAA..AA    Continue at address AA..AA(optional) */
896           /* try to read optional parameter, pc unchanged if no parm */
897           if (hexToInt(&ptr, &addr))
898             {
899               registers[PC] = addr;
900               registers[NPC] = addr + 4;
901             }
902
903 /* Need to flush the instruction cache here, as we may have deposited a
904    breakpoint, and the icache probably has no way of knowing that a data ref to
905    some location may have changed something that is in the instruction cache.
906  */
907
908           flush_i_cache ();
909
910           if (!(registers[DSR] & 0x1) /* DSU enabled? */
911               && !(registers[DCR] & 0x200)) /* Are we in break state? */
912             {                   /* Yes, set the DSU regs */
913               write_asi (1, 0xff00, registers[DIA1]);
914               write_asi (1, 0xff04, registers[DIA2]);
915               write_asi (1, 0xff08, registers[DDA1]);
916               write_asi (1, 0xff0c, registers[DDA2]);
917               write_asi (1, 0xff10, registers[DDV1]);
918               write_asi (1, 0xff14, registers[DDV2]);
919               write_asi (1, 0xff1c, registers[DSR]);
920               write_asi (1, 0xff18, registers[DCR] | 0x200); /* Clear break */
921             }
922
923           return;
924
925           /* kill the program */
926         case 'k' :              /* do nothing */
927           break;
928 #if 0
929         case 't':               /* Test feature */
930           asm (" std %f30,[%sp]");
931           break;
932 #endif
933         case 'r':               /* Reset */
934           asm ("call 0
935                 nop ");
936           break;
937         }                       /* switch */
938
939       /* reply to the request */
940       putpacket(remcomOutBuffer);
941     }
942 }
943
944 /* This function will generate a breakpoint exception.  It is used at the
945    beginning of a program to sync up with a debugger and can be used
946    otherwise as a quick means to stop program execution and "break" into
947    the debugger. */
948
949 void
950 breakpoint()
951 {
952   if (!initialized)
953     return;
954
955   asm(" .globl _breakinst
956
957         _breakinst: ta 1
958       ");
959 }