This commit was generated by cvs2svn to track changes on a CVS vendor
[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  *
54  *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
55  *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
56  *
57  *    c             Resume at current address              SNN   ( signal NN)
58  *    cAA..AA       Continue at address AA..AA             SNN
59  *
60  *    s             Step one instruction                   SNN
61  *    sAA..AA       Step one instruction from AA..AA       SNN
62  *
63  *    k             kill
64  *
65  *    ?             What was the last sigval ?             SNN   (signal NN)
66  *
67  *    bBB..BB       Set baud rate to BB..BB                OK or BNN, then sets
68  *                                                         baud rate
69  *
70  * All commands and responses are sent with a packet which includes a
71  * checksum.  A packet consists of
72  *
73  * $<packet info>#<checksum>.
74  *
75  * where
76  * <packet info> :: <characters representing the command or response>
77  * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
78  *
79  * When a packet is received, it is first acknowledged with either '+' or '-'.
80  * '+' indicates a successful transfer.  '-' indicates a failed transfer.
81  *
82  * Example:
83  *
84  * Host:                  Reply:
85  * $m0,10#2a               +$00010203040506070809101112131415#42
86  *
87  ****************************************************************************/
88
89 #include <string.h>
90 #include <signal.h>
91 #include <sparclite.h>
92
93 /************************************************************************
94  *
95  * external low-level support routines
96  */
97
98 extern void putDebugChar (int c); /* write a single character      */
99 extern int getDebugChar (void); /* read and return a single char */
100
101 /************************************************************************/
102 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
103 /* at least NUMREGBYTES*2 are needed for register packets */
104 #define BUFMAX 2048
105
106 static int initialized = 0;     /* !0 means we've been initialized */
107
108 extern void breakinst ();
109 static void set_mem_fault_trap (int enable);
110 static void get_in_break_mode (void);
111
112 static const char hexchars[]="0123456789abcdef";
113
114 #define NUMREGS 80 
115
116 /* Number of bytes of registers.  */
117 #define NUMREGBYTES (NUMREGS * 4)
118 enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
119                  O0, O1, O2, O3, O4, O5, SP, O7,
120                  L0, L1, L2, L3, L4, L5, L6, L7,
121                  I0, I1, I2, I3, I4, I5, FP, I7,
122
123                  F0, F1, F2, F3, F4, F5, F6, F7,
124                  F8, F9, F10, F11, F12, F13, F14, F15,
125                  F16, F17, F18, F19, F20, F21, F22, F23,
126                  F24, F25, F26, F27, F28, F29, F30, F31,
127                  Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR,
128                  DIA1, DIA2, DDA1, DDA2, DDV1, DDV2, DCR, DSR };
129
130 /***************************  ASSEMBLY CODE MACROS *************************/
131 /*                                                                         */
132
133 extern void trap_low();
134
135 /* Create private copies of common functions used by the stub.  This prevents
136    nasty interactions between app code and the stub (for instance if user steps
137    into strlen, etc..) */
138
139 static int
140 strlen (const char *s)
141 {
142   const char *s1 = s;
143
144   while (*s1++ != '\000');
145
146   return s1 - s;
147 }
148
149 static char *
150 strcpy (char *dst, const char *src)
151 {
152   char *retval = dst;
153
154   while ((*dst++ = *src++) != '\000');
155
156   return retval;
157 }
158
159 static void *
160 memcpy (void *vdst, const void *vsrc, int n)
161 {
162   char *dst = vdst;
163   const char *src = vsrc;
164   char *retval = dst;
165
166   while (n-- > 0)
167     *dst++ = *src++;
168
169   return retval;
170 }
171
172 asm("
173         .reserve trapstack, 1000 * 4, \"bss\", 8
174
175         .data
176         .align  4
177
178 in_trap_handler:
179         .word   0
180
181         .text
182         .align 4
183
184 ! This function is called when any SPARC trap (except window overflow or
185 ! underflow) occurs.  It makes sure that the invalid register window is still
186 ! available before jumping into C code.  It will also restore the world if you
187 ! return from handle_exception.
188 !
189 ! On entry, trap_low expects l1 and l2 to contain pc and npc respectivly.
190 ! Register usage throughout the routine is as follows:
191 !
192 !       l0 - psr
193 !       l1 - pc
194 !       l2 - npc
195 !       l3 - wim
196 !       l4 - scratch and y reg
197 !       l5 - scratch and tbr
198 !       l6 - unused
199 !       l7 - unused
200
201         .globl _trap_low
202 _trap_low:
203         mov     %psr, %l0
204         mov     %wim, %l3
205
206         srl     %l3, %l0, %l4           ! wim >> cwp
207         cmp     %l4, 1
208         bne     window_fine             ! Branch if not in the invalid window
209         nop
210
211 ! Handle window overflow
212
213         mov     %g1, %l4                ! Save g1, we use it to hold the wim
214         srl     %l3, 1, %g1             ! Rotate wim right
215         tst     %g1
216         bg      good_wim                ! Branch if new wim is non-zero
217         nop
218
219 ! At this point, we need to bring a 1 into the high order bit of the wim.
220 ! Since we don't want to make any assumptions about the number of register
221 ! windows, we figure it out dynamically so as to setup the wim correctly.
222
223         not     %g1                     ! Fill g1 with ones
224         mov     %g1, %wim               ! Fill the wim with ones
225         nop
226         nop
227         nop
228         mov     %wim, %g1               ! Read back the wim
229         inc     %g1                     ! Now g1 has 1 just to left of wim
230         srl     %g1, 1, %g1             ! Now put 1 at top of wim
231         mov     %g0, %wim               ! Clear wim so that subsequent save
232         nop                             !  won't trap
233         nop
234         nop
235
236 good_wim:
237         save    %g0, %g0, %g0           ! Slip into next window
238         mov     %g1, %wim               ! Install the new wim
239
240         std     %l0, [%sp + 0 * 4]      ! save L & I registers
241         std     %l2, [%sp + 2 * 4]
242         std     %l4, [%sp + 4 * 4]
243         std     %l6, [%sp + 6 * 4]
244
245         std     %i0, [%sp + 8 * 4]
246         std     %i2, [%sp + 10 * 4]
247         std     %i4, [%sp + 12 * 4]
248         std     %i6, [%sp + 14 * 4]
249
250         restore                         ! Go back to trap window.
251         mov     %l4, %g1                ! Restore %g1
252
253 window_fine:
254         sethi   %hi(in_trap_handler), %l4
255         ld      [%lo(in_trap_handler) + %l4], %l5
256         tst     %l5
257         bg      recursive_trap
258         inc     %l5
259
260         set     trapstack+1000*4, %sp   ! Switch to trap stack
261
262 recursive_trap:
263         st      %l5, [%lo(in_trap_handler) + %l4]
264         sub     %sp,(16+1+6+1+80)*4,%sp ! Make room for input & locals
265                                         ! + hidden arg + arg spill
266                                         ! + doubleword alignment
267                                         ! + registers[72] local var
268
269         std     %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
270         std     %g2, [%sp + (24 + 2) * 4]
271         std     %g4, [%sp + (24 + 4) * 4]
272         std     %g6, [%sp + (24 + 6) * 4]
273
274         std     %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
275         std     %i2, [%sp + (24 + 10) * 4]
276         std     %i4, [%sp + (24 + 12) * 4]
277         std     %i6, [%sp + (24 + 14) * 4]
278
279         mov     %y, %l4
280         mov     %tbr, %l5
281         st      %l4, [%sp + (24 + 64) * 4] ! Y
282         st      %l0, [%sp + (24 + 65) * 4] ! PSR
283         st      %l3, [%sp + (24 + 66) * 4] ! WIM
284         st      %l5, [%sp + (24 + 67) * 4] ! TBR
285         st      %l1, [%sp + (24 + 68) * 4] ! PC
286         st      %l2, [%sp + (24 + 69) * 4] ! NPC
287
288         or      %l0, 0xf20, %l4
289         mov     %l4, %psr               ! Turn on traps, disable interrupts
290
291         set     0x1000, %l1
292         btst    %l1, %l0                ! FP enabled?
293         be      no_fpstore
294         nop
295
296 ! Must save fsr first, to flush the FQ.  This may cause a deferred fp trap, so
297 ! traps must be enabled to allow the trap handler to clean things up.
298
299         st      %fsr, [%sp + (24 + 70) * 4]
300
301         std     %f0, [%sp + (24 + 32) * 4]
302         std     %f2, [%sp + (24 + 34) * 4]
303         std     %f4, [%sp + (24 + 36) * 4]
304         std     %f6, [%sp + (24 + 38) * 4]
305         std     %f8, [%sp + (24 + 40) * 4]
306         std     %f10, [%sp + (24 + 42) * 4]
307         std     %f12, [%sp + (24 + 44) * 4]
308         std     %f14, [%sp + (24 + 46) * 4]
309         std     %f16, [%sp + (24 + 48) * 4]
310         std     %f18, [%sp + (24 + 50) * 4]
311         std     %f20, [%sp + (24 + 52) * 4]
312         std     %f22, [%sp + (24 + 54) * 4]
313         std     %f24, [%sp + (24 + 56) * 4]
314         std     %f26, [%sp + (24 + 58) * 4]
315         std     %f28, [%sp + (24 + 60) * 4]
316         std     %f30, [%sp + (24 + 62) * 4]
317 no_fpstore:
318
319         call    _handle_exception
320         add     %sp, 24 * 4, %o0        ! Pass address of registers
321
322 ! Reload all of the registers that aren't on the stack
323
324         ld      [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
325         ldd     [%sp + (24 + 2) * 4], %g2
326         ldd     [%sp + (24 + 4) * 4], %g4
327         ldd     [%sp + (24 + 6) * 4], %g6
328
329         ldd     [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
330         ldd     [%sp + (24 + 10) * 4], %i2
331         ldd     [%sp + (24 + 12) * 4], %i4
332         ldd     [%sp + (24 + 14) * 4], %i6
333
334
335         ldd     [%sp + (24 + 64) * 4], %l0 ! Y & PSR
336         ldd     [%sp + (24 + 68) * 4], %l2 ! PC & NPC
337
338         set     0x1000, %l5
339         btst    %l5, %l1                ! FP enabled?
340         be      no_fpreload
341         nop
342
343         ldd     [%sp + (24 + 32) * 4], %f0
344         ldd     [%sp + (24 + 34) * 4], %f2
345         ldd     [%sp + (24 + 36) * 4], %f4
346         ldd     [%sp + (24 + 38) * 4], %f6
347         ldd     [%sp + (24 + 40) * 4], %f8
348         ldd     [%sp + (24 + 42) * 4], %f10
349         ldd     [%sp + (24 + 44) * 4], %f12
350         ldd     [%sp + (24 + 46) * 4], %f14
351         ldd     [%sp + (24 + 48) * 4], %f16
352         ldd     [%sp + (24 + 50) * 4], %f18
353         ldd     [%sp + (24 + 52) * 4], %f20
354         ldd     [%sp + (24 + 54) * 4], %f22
355         ldd     [%sp + (24 + 56) * 4], %f24
356         ldd     [%sp + (24 + 58) * 4], %f26
357         ldd     [%sp + (24 + 60) * 4], %f28
358         ldd     [%sp + (24 + 62) * 4], %f30
359
360         ld      [%sp + (24 + 70) * 4], %fsr
361 no_fpreload:
362
363         restore                         ! Ensure that previous window is valid
364         save    %g0, %g0, %g0           !  by causing a window_underflow trap
365
366         mov     %l0, %y
367         mov     %l1, %psr               ! Make sure that traps are disabled
368                                         ! for rett
369         sethi   %hi(in_trap_handler), %l4
370         ld      [%lo(in_trap_handler) + %l4], %l5
371         dec     %l5
372         st      %l5, [%lo(in_trap_handler) + %l4]
373
374         jmpl    %l2, %g0                ! Restore old PC
375         rett    %l3                     ! Restore old nPC
376 ");
377
378 /* Convert ch from a hex digit to an int */
379
380 static int
381 hex(ch)
382      unsigned char ch;
383 {
384   if (ch >= 'a' && ch <= 'f')
385     return ch-'a'+10;
386   if (ch >= '0' && ch <= '9')
387     return ch-'0';
388   if (ch >= 'A' && ch <= 'F')
389     return ch-'A'+10;
390   return -1;
391 }
392
393 /* scan for the sequence $<data>#<checksum>     */
394
395 static void
396 getpacket(buffer)
397      char *buffer;
398 {
399   unsigned char checksum;
400   unsigned char xmitcsum;
401   int i;
402   int count;
403   unsigned char ch;
404
405   do
406     {
407       /* wait around for the start character, ignore all other characters */
408       while ((ch = (getDebugChar() & 0x7f)) != '$') ;
409
410       checksum = 0;
411       xmitcsum = -1;
412
413       count = 0;
414
415       /* now, read until a # or end of buffer is found */
416       while (count < BUFMAX)
417         {
418           ch = getDebugChar() & 0x7f;
419           if (ch == '#')
420             break;
421           checksum = checksum + ch;
422           buffer[count] = ch;
423           count = count + 1;
424         }
425
426       if (count >= BUFMAX)
427         continue;
428
429       buffer[count] = 0;
430
431       if (ch == '#')
432         {
433           xmitcsum = hex(getDebugChar() & 0x7f) << 4;
434           xmitcsum |= hex(getDebugChar() & 0x7f);
435 #if 0
436           /* Humans shouldn't have to figure out checksums to type to it. */
437           putDebugChar ('+');
438           return;
439 #endif
440           if (checksum != xmitcsum)
441             putDebugChar('-');  /* failed checksum */
442           else
443             {
444               putDebugChar('+'); /* successful transfer */
445               /* if a sequence char is present, reply the sequence ID */
446               if (buffer[2] == ':')
447                 {
448                   putDebugChar(buffer[0]);
449                   putDebugChar(buffer[1]);
450                   /* remove sequence chars from buffer */
451                   count = strlen(buffer);
452                   for (i=3; i <= count; i++)
453                     buffer[i-3] = buffer[i];
454                 }
455             }
456         }
457     }
458   while (checksum != xmitcsum);
459 }
460
461 /* send the packet in buffer.  */
462
463 static void
464 putpacket(buffer)
465      unsigned char *buffer;
466 {
467   unsigned char checksum;
468   int count;
469   unsigned char ch;
470
471   /*  $<packet info>#<checksum>. */
472   do
473     {
474       putDebugChar('$');
475       checksum = 0;
476       count = 0;
477
478       while (ch = buffer[count])
479         {
480           putDebugChar (ch);
481           checksum += ch;
482           count += 1;
483         }
484
485       putDebugChar('#');
486       putDebugChar(hexchars[checksum >> 4]);
487       putDebugChar(hexchars[checksum & 0xf]);
488
489     }
490   while ((getDebugChar() & 0x7f) != '+');
491 }
492
493 static char remcomInBuffer[BUFMAX];
494 static char remcomOutBuffer[BUFMAX];
495
496 /* Indicate to caller of mem2hex or hex2mem that there has been an
497    error.  */
498 static volatile int mem_err = 0;
499
500 /* Convert the memory pointed to by mem into hex, placing result in buf.
501  * Return a pointer to the last char put in buf (null), in case of mem fault,
502  * return 0.
503  * If MAY_FAULT is non-zero, then we will handle memory faults by returning
504  * a 0, else treat a fault like any other fault in the stub.
505  */
506
507 static unsigned char *
508 mem2hex(mem, buf, count, may_fault)
509      unsigned char *mem;
510      unsigned char *buf;
511      int count;
512      int may_fault;
513 {
514   unsigned char ch;
515
516   set_mem_fault_trap(may_fault);
517
518   while (count-- > 0)
519     {
520       ch = *mem++;
521       if (mem_err)
522         return 0;
523       *buf++ = hexchars[ch >> 4];
524       *buf++ = hexchars[ch & 0xf];
525     }
526
527   *buf = 0;
528
529   set_mem_fault_trap(0);
530
531   return buf;
532 }
533
534 /* convert the hex array pointed to by buf into binary to be placed in mem
535  * return a pointer to the character AFTER the last byte written */
536
537 static char *
538 hex2mem(buf, mem, count, may_fault)
539      unsigned char *buf;
540      unsigned char *mem;
541      int count;
542      int may_fault;
543 {
544   int i;
545   unsigned char ch;
546
547   set_mem_fault_trap(may_fault);
548
549   for (i=0; i<count; i++)
550     {
551       ch = hex(*buf++) << 4;
552       ch |= hex(*buf++);
553       *mem++ = ch;
554       if (mem_err)
555         return 0;
556     }
557
558   set_mem_fault_trap(0);
559
560   return mem;
561 }
562
563 /* This table contains the mapping between SPARC hardware trap types, and
564    signals, which are primarily what GDB understands.  It also indicates
565    which hardware traps we need to commandeer when initializing the stub. */
566
567 static struct hard_trap_info
568 {
569   unsigned char tt;             /* Trap type code for SPARClite */
570   unsigned char signo;          /* Signal that we map this trap into */
571 } hard_trap_info[] = {
572   {0x01, SIGSEGV},              /* instruction access error */
573   {0x02, SIGILL},               /* privileged instruction */
574   {0x03, SIGILL},               /* illegal instruction */
575   {0x04, SIGEMT},               /* fp disabled */
576   {0x07, SIGBUS},               /* mem address not aligned */
577   {0x09, SIGSEGV},              /* data access exception */
578   {0x0a, SIGEMT},               /* tag overflow */
579   {0x20, SIGBUS},               /* r register access error */
580   {0x21, SIGBUS},               /* instruction access error */
581   {0x24, SIGEMT},               /* cp disabled */
582   {0x29, SIGBUS},               /* data access error */
583   {0x2a, SIGFPE},               /* divide by zero */
584   {0x2b, SIGBUS},               /* data store error */
585   {0x80+1, SIGTRAP},            /* ta 1 - normal breakpoint instruction */
586   {0xff, SIGTRAP},              /* hardware breakpoint */
587   {0, 0}                        /* Must be last */
588 };
589
590 /* Set up exception handlers for tracing and breakpoints */
591
592 void
593 set_debug_traps()
594 {
595   struct hard_trap_info *ht;
596
597 /* Only setup fp traps if the FP is disabled.  */
598
599   for (ht = hard_trap_info;
600        ht->tt != 0 && ht->signo != 0;
601        ht++)
602     if (ht->tt != 4 || ! (read_psr () & 0x1000))
603       exceptionHandler(ht->tt, trap_low);
604
605   /* In case GDB is started before us, ack any packets (presumably
606      "$?#xx") sitting there.  */
607
608   putDebugChar ('+');
609
610   initialized = 1;
611 }
612
613 asm ("
614 ! Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
615 ! assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
616 ! 0 would ever contain code that could mem fault.  This routine will skip
617 ! past the faulting instruction after setting mem_err.
618
619         .text
620         .align 4
621
622 _fltr_set_mem_err:
623         sethi %hi(_mem_err), %l0
624         st %l1, [%l0 + %lo(_mem_err)]
625         jmpl %l2, %g0
626         rett %l2+4
627 ");
628
629 static void
630 set_mem_fault_trap(enable)
631      int enable;
632 {
633   extern void fltr_set_mem_err();
634   mem_err = 0;
635
636   if (enable)
637     exceptionHandler(9, fltr_set_mem_err);
638   else
639     exceptionHandler(9, trap_low);
640 }
641
642 asm ("
643         .text
644         .align 4
645
646 _dummy_hw_breakpoint:
647         jmpl %l2, %g0
648         rett %l2+4
649         nop
650         nop
651 ");
652
653 static void
654 get_in_break_mode()
655 {
656   extern void dummy_hw_breakpoint();
657
658   exceptionHandler (255, dummy_hw_breakpoint);
659
660   asm ("ta 255");
661
662   exceptionHandler (255, trap_low);
663 }
664
665 /* Convert the SPARC hardware trap type code to a unix signal number. */
666
667 static int
668 computeSignal(tt)
669      int tt;
670 {
671   struct hard_trap_info *ht;
672
673   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
674     if (ht->tt == tt)
675       return ht->signo;
676
677   return SIGHUP;                /* default for things we don't know about */
678 }
679
680 /*
681  * While we find nice hex chars, build an int.
682  * Return number of chars processed.
683  */
684
685 static int
686 hexToInt(char **ptr, int *intValue)
687 {
688   int numChars = 0;
689   int hexValue;
690
691   *intValue = 0;
692
693   while (**ptr)
694     {
695       hexValue = hex(**ptr);
696       if (hexValue < 0)
697         break;
698
699       *intValue = (*intValue << 4) | hexValue;
700       numChars ++;
701
702       (*ptr)++;
703     }
704
705   return (numChars);
706 }
707
708 /*
709  * This function does all command procesing for interfacing to gdb.  It
710  * returns 1 if you should skip the instruction at the trap address, 0
711  * otherwise.
712  */
713
714 static void
715 handle_exception (registers)
716      unsigned long *registers;
717 {
718   int tt;                       /* Trap type */
719   int sigval;
720   int addr;
721   int length;
722   char *ptr;
723   unsigned long *sp;
724   unsigned long dsr;
725
726 /* First, we must force all of the windows to be spilled out */
727
728   asm(" save %sp, -64, %sp
729         save %sp, -64, %sp
730         save %sp, -64, %sp
731         save %sp, -64, %sp
732         save %sp, -64, %sp
733         save %sp, -64, %sp
734         save %sp, -64, %sp
735         save %sp, -64, %sp
736         restore
737         restore
738         restore
739         restore
740         restore
741         restore
742         restore
743         restore
744 ");
745
746   get_in_break_mode ();         /* Enable DSU register writes */
747
748   registers[DIA1] = read_asi (1, 0xff00);
749   registers[DIA2] = read_asi (1, 0xff04);
750   registers[DDA1] = read_asi (1, 0xff08);
751   registers[DDA2] = read_asi (1, 0xff0c);
752   registers[DDV1] = read_asi (1, 0xff10);
753   registers[DDV2] = read_asi (1, 0xff14);
754   registers[DCR] = read_asi (1, 0xff18);
755   registers[DSR] = read_asi (1, 0xff1c);
756
757   if (registers[PC] == (unsigned long)breakinst)
758     {
759       registers[PC] = registers[NPC];
760       registers[NPC] += 4;
761     }
762   sp = (unsigned long *)registers[SP];
763
764   dsr = (unsigned long)registers[DSR];
765   if (dsr & 0x3c)
766     tt = 255;
767   else
768     tt = (registers[TBR] >> 4) & 0xff;
769
770   /* reply to host that an exception has occurred */
771   sigval = computeSignal(tt);
772   ptr = remcomOutBuffer;
773
774   *ptr++ = 'T';
775   *ptr++ = hexchars[sigval >> 4];
776   *ptr++ = hexchars[sigval & 0xf];
777
778   *ptr++ = hexchars[PC >> 4];
779   *ptr++ = hexchars[PC & 0xf];
780   *ptr++ = ':';
781   ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
782   *ptr++ = ';';
783
784   *ptr++ = hexchars[FP >> 4];
785   *ptr++ = hexchars[FP & 0xf];
786   *ptr++ = ':';
787   ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
788   *ptr++ = ';';
789
790   *ptr++ = hexchars[SP >> 4];
791   *ptr++ = hexchars[SP & 0xf];
792   *ptr++ = ':';
793   ptr = mem2hex((char *)&sp, ptr, 4, 0);
794   *ptr++ = ';';
795
796   *ptr++ = hexchars[NPC >> 4];
797   *ptr++ = hexchars[NPC & 0xf];
798   *ptr++ = ':';
799   ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
800   *ptr++ = ';';
801
802   *ptr++ = hexchars[O7 >> 4];
803   *ptr++ = hexchars[O7 & 0xf];
804   *ptr++ = ':';
805   ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
806   *ptr++ = ';';
807
808   *ptr++ = 0;
809
810   putpacket(remcomOutBuffer);
811
812   while (1)
813     {
814       remcomOutBuffer[0] = 0;
815
816       getpacket(remcomInBuffer);
817       switch (remcomInBuffer[0])
818         {
819         case '?':
820           remcomOutBuffer[0] = 'S';
821           remcomOutBuffer[1] = hexchars[sigval >> 4];
822           remcomOutBuffer[2] = hexchars[sigval & 0xf];
823           remcomOutBuffer[3] = 0;
824           break;
825
826         case 'd':
827                                 /* toggle debug flag */
828           break;
829
830         case 'g':               /* return the value of the CPU registers */
831           memcpy (&registers[L0], sp, 16 * 4); /* Copy L & I regs from stack */
832           mem2hex ((char *)registers, remcomOutBuffer, NUMREGBYTES, 0);
833           break;
834
835         case 'G':               /* Set the value of all registers */
836         case 'P':               /* Set the value of one register */
837           {
838             unsigned long *newsp, psr;
839
840             psr = registers[PSR];
841
842             ptr = &remcomInBuffer[1];
843
844             if (remcomInBuffer[0] == 'P')
845               {
846                 int regno;
847
848                 if (hexToInt (&ptr, &regno)
849                     && *ptr++ == '=')
850                   if (regno >= L0 && regno <= I7)
851                     hex2mem (ptr, sp + regno - L0, 4, 0);
852                   else
853                     hex2mem (ptr, (char *)&registers[regno], 4, 0);
854                 else
855                   {
856                     strcpy (remcomOutBuffer, "P01");
857                     break;
858                   }
859               }
860             else
861               {
862                 hex2mem (ptr, (char *)registers, NUMREGBYTES, 0);
863                 memcpy (sp, &registers[L0], 16 * 4); /* Copy L & I regs to stack */
864               }
865
866             /* See if the stack pointer has moved.  If so, then copy the saved
867                locals and ins to the new location.  This keeps the window
868                overflow and underflow routines happy.  */
869
870             newsp = (unsigned long *)registers[SP];
871             if (sp != newsp)
872               sp = memcpy(newsp, sp, 16 * 4);
873
874             /* Don't allow CWP to be modified. */
875
876             if (psr != registers[PSR])
877               registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
878
879             strcpy(remcomOutBuffer,"OK");
880           }
881           break;
882
883         case 'm':         /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
884           /* Try to read %x,%x.  */
885
886           ptr = &remcomInBuffer[1];
887
888           if (hexToInt(&ptr, &addr)
889               && *ptr++ == ','
890               && hexToInt(&ptr, &length))
891             {
892               if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
893                 break;
894
895               strcpy (remcomOutBuffer, "E03");
896             }
897           else
898             strcpy(remcomOutBuffer,"E01");
899           break;
900
901         case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
902           /* Try to read '%x,%x:'.  */
903
904           ptr = &remcomInBuffer[1];
905
906           if (hexToInt(&ptr, &addr)
907               && *ptr++ == ','
908               && hexToInt(&ptr, &length)
909               && *ptr++ == ':')
910             {
911               if (hex2mem(ptr, (char *)addr, length, 1))
912                 strcpy(remcomOutBuffer, "OK");
913               else
914                 strcpy(remcomOutBuffer, "E03");
915             }
916           else
917             strcpy(remcomOutBuffer, "E02");
918           break;
919
920         case 'c':    /* cAA..AA    Continue at address AA..AA(optional) */
921           /* try to read optional parameter, pc unchanged if no parm */
922
923           ptr = &remcomInBuffer[1];
924           if (hexToInt(&ptr, &addr))
925             {
926               registers[PC] = addr;
927               registers[NPC] = addr + 4;
928             }
929
930 /* Need to flush the instruction cache here, as we may have deposited a
931    breakpoint, and the icache probably has no way of knowing that a data ref to
932    some location may have changed something that is in the instruction cache.
933  */
934
935           flush_i_cache ();
936
937           if (!(registers[DSR] & 0x1) /* DSU enabled? */
938               && !(registers[DCR] & 0x200)) /* Are we in break state? */
939             {                   /* Yes, set the DSU regs */
940               write_asi (1, 0xff00, registers[DIA1]);
941               write_asi (1, 0xff04, registers[DIA2]);
942               write_asi (1, 0xff08, registers[DDA1]);
943               write_asi (1, 0xff0c, registers[DDA2]);
944               write_asi (1, 0xff10, registers[DDV1]);
945               write_asi (1, 0xff14, registers[DDV2]);
946               write_asi (1, 0xff1c, registers[DSR]);
947               write_asi (1, 0xff18, registers[DCR] | 0x200); /* Clear break */
948             }
949
950           return;
951
952           /* kill the program */
953         case 'k' :              /* do nothing */
954           break;
955 #if 0
956         case 't':               /* Test feature */
957           asm (" std %f30,[%sp]");
958           break;
959 #endif
960         case 'r':               /* Reset */
961           asm ("call 0
962                 nop ");
963           break;
964
965 #if 0
966 Disabled until we can unscrew this properly
967
968         case 'b':         /* bBB...  Set baud rate to BB... */
969           {
970             int baudrate;
971             extern void set_timer_3();
972
973             ptr = &remcomInBuffer[1];
974             if (!hexToInt(&ptr, &baudrate))
975               {
976                 strcpy(remcomOutBuffer,"B01");
977                 break;
978               }
979
980             /* Convert baud rate to uart clock divider */
981             switch (baudrate)
982               {
983               case 38400:
984                 baudrate = 16;
985                 break;
986               case 19200:
987                 baudrate = 33;
988                 break;
989               case 9600:
990                 baudrate = 65;
991                 break;
992               default:
993                 strcpy(remcomOutBuffer,"B02");
994                 goto x1;
995               }
996
997             putpacket("OK");    /* Ack before changing speed */
998             set_timer_3(baudrate); /* Set it */
999           }
1000 x1:       break;
1001 #endif
1002         }                       /* switch */
1003
1004       /* reply to the request */
1005       putpacket(remcomOutBuffer);
1006     }
1007 }
1008
1009 /* This function will generate a breakpoint exception.  It is used at the
1010    beginning of a program to sync up with a debugger and can be used
1011    otherwise as a quick means to stop program execution and "break" into
1012    the debugger. */
1013
1014 void
1015 breakpoint()
1016 {
1017   if (!initialized)
1018     return;
1019
1020   asm(" .globl _breakinst
1021
1022         _breakinst: ta 1
1023       ");
1024 }