OSDN Git Service

Initial revision
[pf3gnuchains/pf3gnuchains3x.git] / gdb / sparclet-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 P01 (???)
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  *    bBB..BB       Set baud rate to BB..BB                OK or BNN, then sets
69  *                                                         baud rate
70  *
71  * All commands and responses are sent with a packet which includes a
72  * checksum.  A packet consists of
73  *
74  * $<packet info>#<checksum>.
75  *
76  * where
77  * <packet info> :: <characters representing the command or response>
78  * <checksum>    :: <two hex digits computed as modulo 256 sum of <packetinfo>>
79  *
80  * When a packet is received, it is first acknowledged with either '+' or '-'.
81  * '+' indicates a successful transfer.  '-' indicates a failed transfer.
82  *
83  * Example:
84  *
85  * Host:                  Reply:
86  * $m0,10#2a               +$00010203040506070809101112131415#42
87  *
88  ****************************************************************************/
89
90 #include <string.h>
91 #include <signal.h>
92
93 /************************************************************************
94  *
95  * external low-level support routines
96  */
97
98 extern void putDebugChar();     /* write a single character      */
99 extern int getDebugChar();      /* 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 static int remote_debug = 0;    /* turn on verbose debugging */
108
109 extern void breakinst();
110 void _cprint();
111 static void hw_breakpoint();
112 static void set_mem_fault_trap();
113 static void get_in_break_mode();
114 static unsigned char *mem2hex();
115
116 static const char hexchars[]="0123456789abcdef";
117
118 #define NUMREGS 121
119
120 static unsigned long saved_stack_pointer;
121
122 /* Number of bytes of registers.  */
123 #define NUMREGBYTES (NUMREGS * 4)
124 enum regnames { G0, G1, G2, G3, G4, G5, G6, G7,
125                 O0, O1, O2, O3, O4, O5, SP, O7,
126                 L0, L1, L2, L3, L4, L5, L6, L7,
127                 I0, I1, I2, I3, I4, I5, FP, I7,
128
129                 F0, F1, F2, F3, F4, F5, F6, F7,
130                 F8, F9, F10, F11, F12, F13, F14, F15,
131                 F16, F17, F18, F19, F20, F21, F22, F23,
132                 F24, F25, F26, F27, F28, F29, F30, F31,
133
134                 Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR,
135                 CCSR, CCPR, CCCRCR, CCOR, CCOBR, CCIBR, CCIR, UNUSED1,
136
137                 ASR1, ASR15, ASR17, ASR18, ASR19, ASR20, ASR21, ASR22, 
138                 /* the following not actually implemented */
139                 AWR0,  AWR1,  AWR2,  AWR3,  AWR4,  AWR5,  AWR6,  AWR7,  
140                 AWR8,  AWR9,  AWR10, AWR11, AWR12, AWR13, AWR14, AWR15,  
141                 AWR16, AWR17, AWR18, AWR19, AWR20, AWR21, AWR22, AWR23,  
142                 AWR24, AWR25, AWR26, AWR27, AWR28, AWR29, AWR30, AWR31,  
143                 APSR
144 };
145
146 /***************************  ASSEMBLY CODE MACROS *************************/
147 /*                                                                         */
148
149 extern void trap_low();
150
151 asm("
152         .reserve trapstack, 1000 * 4, \"bss\", 8
153
154         .data
155         .align  4
156
157 in_trap_handler:
158         .word   0
159
160         .text
161         .align 4
162
163 ! This function is called when any SPARC trap (except window overflow or
164 ! underflow) occurs.  It makes sure that the invalid register window is still
165 ! available before jumping into C code.  It will also restore the world if you
166 ! return from handle_exception.
167 !
168 ! On entry, trap_low expects l1 and l2 to contain pc and npc respectivly.
169
170         .globl _trap_low
171 _trap_low:
172         mov     %psr, %l0
173         mov     %wim, %l3
174
175         srl     %l3, %l0, %l4           ! wim >> cwp
176         and     %l4, 0xff, %l4          ! Mask off windows 28, 29
177         cmp     %l4, 1
178         bne     window_fine             ! Branch if not in the invalid window
179         nop
180
181 ! Handle window overflow
182
183         mov     %g1, %l4                ! Save g1, we use it to hold the wim
184         srl     %l3, 1, %g1             ! Rotate wim right
185         and     %g1, 0xff, %g1          ! Mask off windows 28, 29
186         tst     %g1
187         bg      good_wim                ! Branch if new wim is non-zero
188         nop
189
190 ! At this point, we need to bring a 1 into the high order bit of the wim.
191 ! Since we don't want to make any assumptions about the number of register
192 ! windows, we figure it out dynamically so as to setup the wim correctly.
193
194         ! The normal way doesn't work on the sparclet as register windows
195         ! 28 and 29 are special purpose windows.
196         !not    %g1                     ! Fill g1 with ones
197         !mov    %g1, %wim               ! Fill the wim with ones
198         !nop
199         !nop
200         !nop
201         !mov    %wim, %g1               ! Read back the wim
202         !inc    %g1                     ! Now g1 has 1 just to left of wim
203         !srl    %g1, 1, %g1             ! Now put 1 at top of wim
204
205         mov     0x80, %g1               ! Hack for sparclet
206
207         ! This doesn't work on the sparclet.
208         !mov    %g0, %wim               ! Clear wim so that subsequent save
209                                         !  won't trap
210         andn    %l3, 0xff, %l5          ! Clear wim but not windows 28, 29
211         mov     %l5, %wim
212         nop
213         nop
214         nop
215
216 good_wim:
217         save    %g0, %g0, %g0           ! Slip into next window
218         mov     %g1, %wim               ! Install the new wim
219
220         std     %l0, [%sp + 0 * 4]      ! save L & I registers
221         std     %l2, [%sp + 2 * 4]
222         std     %l4, [%sp + 4 * 4]
223         std     %l6, [%sp + 6 * 4]
224
225         std     %i0, [%sp + 8 * 4]
226         std     %i2, [%sp + 10 * 4]
227         std     %i4, [%sp + 12 * 4]
228         std     %i6, [%sp + 14 * 4]
229
230         restore                         ! Go back to trap window.
231         mov     %l4, %g1                ! Restore %g1
232
233 window_fine:
234         sethi   %hi(in_trap_handler), %l4
235         ld      [%lo(in_trap_handler) + %l4], %l5
236         tst     %l5
237         bg      recursive_trap
238         inc     %l5
239
240         set     trapstack+1000*4, %sp   ! Switch to trap stack
241
242 recursive_trap:
243         st      %l5, [%lo(in_trap_handler) + %l4]
244         sub     %sp,(16+1+6+1+88)*4,%sp ! Make room for input & locals
245                                         ! + hidden arg + arg spill
246                                         ! + doubleword alignment
247                                         ! + registers[121]
248
249         std     %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
250         std     %g2, [%sp + (24 + 2) * 4]
251         std     %g4, [%sp + (24 + 4) * 4]
252         std     %g6, [%sp + (24 + 6) * 4]
253
254         std     %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
255         std     %i2, [%sp + (24 + 10) * 4]
256         std     %i4, [%sp + (24 + 12) * 4]
257         std     %i6, [%sp + (24 + 14) * 4]
258
259         ! FP regs (sparclet doesn't have fpu)
260
261         mov     %y, %l4
262         mov     %tbr, %l5
263         st      %l4, [%sp + (24 + 64) * 4] ! Y
264         st      %l0, [%sp + (24 + 65) * 4] ! PSR
265         st      %l3, [%sp + (24 + 66) * 4] ! WIM
266         st      %l5, [%sp + (24 + 67) * 4] ! TBR
267         st      %l1, [%sp + (24 + 68) * 4] ! PC
268         st      %l2, [%sp + (24 + 69) * 4] ! NPC
269                                         ! CPSR and FPSR not impl
270         or      %l0, 0xf20, %l4
271         mov     %l4, %psr               ! Turn on traps, disable interrupts
272         nop
273         nop
274         nop
275
276 ! Save coprocessor state.
277 ! See SK/demo/hdlc_demo/ldc_swap_context.S.
278
279         mov     %psr, %l0
280         sethi   %hi(0x2000), %l5                ! EC bit in PSR
281         or      %l5, %l0, %l5
282         mov     %l5, %psr                       ! enable coprocessor
283         nop                     ! 3 nops after write to %psr (needed?)
284         nop
285         nop
286         crdcxt  %ccsr, %l1                      ! capture CCSR
287         mov     0x6, %l2
288         cwrcxt  %l2, %ccsr      ! set CCP state machine for CCFR
289         crdcxt  %ccfr, %l2                      ! capture CCOR
290         cwrcxt  %l2, %ccfr                      ! tickle  CCFR
291         crdcxt  %ccfr, %l3                      ! capture CCOBR
292         cwrcxt  %l3, %ccfr                      ! tickle  CCFR
293         crdcxt  %ccfr, %l4                      ! capture CCIBR
294         cwrcxt  %l4, %ccfr                      ! tickle  CCFR
295         crdcxt  %ccfr, %l5                      ! capture CCIR
296         cwrcxt  %l5, %ccfr                      ! tickle  CCFR
297         crdcxt  %ccpr, %l6                      ! capture CCPR
298         crdcxt  %cccrcr, %l7                    ! capture CCCRCR
299         st      %l1, [%sp + (24 + 72) * 4]      ! save CCSR
300         st      %l2, [%sp + (24 + 75) * 4]      ! save CCOR
301         st      %l3, [%sp + (24 + 76) * 4]      ! save CCOBR
302         st      %l4, [%sp + (24 + 77) * 4]      ! save CCIBR
303         st      %l5, [%sp + (24 + 78) * 4]      ! save CCIR
304         st      %l6, [%sp + (24 + 73) * 4]      ! save CCPR
305         st      %l7, [%sp + (24 + 74) * 4]      ! save CCCRCR
306         mov     %l0, %psr                       ! restore original PSR
307         nop                     ! 3 nops after write to %psr (needed?)
308         nop
309         nop
310
311 ! End of saving coprocessor state.
312 ! Save asr regs
313
314 ! Part of this is silly -- we should not display ASR15 or ASR19 at all.
315
316         sethi   %hi(0x01000000), %l6
317         st      %l6, [%sp + (24 + 81) * 4]      ! ASR15 == NOP
318         sethi   %hi(0xdeadc0de), %l6
319         or      %l6, %lo(0xdeadc0de), %l6
320         st      %l6, [%sp + (24 + 84) * 4]      ! ASR19 == DEADC0DE
321
322         rd      %asr1, %l4
323         st      %l4, [%sp + (24 + 80) * 4]
324 !       rd      %asr15, %l4                     ! must not read ASR15
325 !       st      %l4, [%sp + (24 + 81) * 4]      ! (illegal instr trap)
326         rd      %asr17, %l4
327         st      %l4, [%sp + (24 + 82) * 4]
328         rd      %asr18, %l4
329         st      %l4, [%sp + (24 + 83) * 4]
330 !       rd      %asr19, %l4                     ! must not read asr19
331 !       st      %l4, [%sp + (24 + 84) * 4]      ! (halts the CPU)
332         rd      %asr20, %l4
333         st      %l4, [%sp + (24 + 85) * 4]
334         rd      %asr21, %l4
335         st      %l4, [%sp + (24 + 86) * 4]
336         rd      %asr22, %l4
337         st      %l4, [%sp + (24 + 87) * 4]
338
339 ! End of saving asr regs
340
341         call    _handle_exception
342         add     %sp, 24 * 4, %o0        ! Pass address of registers
343
344 ! Reload all of the registers that aren't on the stack
345
346         ld      [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
347         ldd     [%sp + (24 + 2) * 4], %g2
348         ldd     [%sp + (24 + 4) * 4], %g4
349         ldd     [%sp + (24 + 6) * 4], %g6
350
351         ldd     [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
352         ldd     [%sp + (24 + 10) * 4], %i2
353         ldd     [%sp + (24 + 12) * 4], %i4
354         ldd     [%sp + (24 + 14) * 4], %i6
355
356         ! FP regs (sparclet doesn't have fpu)
357
358 ! Update the coprocessor registers.
359 ! See SK/demo/hdlc_demo/ldc_swap_context.S.
360
361         mov     %psr, %l0
362         sethi   %hi(0x2000), %l5                ! EC bit in PSR
363         or      %l5, %l0, %l5
364         mov     %l5, %psr                       ! enable coprocessor
365         nop                     ! 3 nops after write to %psr (needed?)
366         nop
367         nop
368
369         mov 0x6, %l2
370         cwrcxt  %l2, %ccsr      ! set CCP state machine for CCFR
371
372         ld      [%sp + (24 + 72) * 4], %l1      ! saved CCSR
373         ld      [%sp + (24 + 75) * 4], %l2      ! saved CCOR
374         ld      [%sp + (24 + 76) * 4], %l3      ! saved CCOBR
375         ld      [%sp + (24 + 77) * 4], %l4      ! saved CCIBR
376         ld      [%sp + (24 + 78) * 4], %l5      ! saved CCIR
377         ld      [%sp + (24 + 73) * 4], %l6      ! saved CCPR
378         ld      [%sp + (24 + 74) * 4], %l7      ! saved CCCRCR
379
380         cwrcxt  %l2, %ccfr                      ! restore CCOR
381         cwrcxt  %l3, %ccfr                      ! restore CCOBR
382         cwrcxt  %l4, %ccfr                      ! restore CCIBR
383         cwrcxt  %l5, %ccfr                      ! restore CCIR
384         cwrcxt  %l6, %ccpr                      ! restore CCPR
385         cwrcxt  %l7, %cccrcr                    ! restore CCCRCR
386         cwrcxt  %l1, %ccsr                      ! restore CCSR
387
388         mov %l0, %psr                           ! restore PSR
389         nop             ! 3 nops after write to %psr (needed?)
390         nop
391         nop
392
393 ! End of coprocessor handling stuff.
394 ! Update asr regs
395
396         ld      [%sp + (24 + 80) * 4], %l4
397         wr      %l4, %asr1
398 !       ld      [%sp + (24 + 81) * 4], %l4      ! can't write asr15
399 !       wr      %l4, %asr15
400         ld      [%sp + (24 + 82) * 4], %l4
401         wr      %l4, %asr17
402         ld      [%sp + (24 + 83) * 4], %l4
403         wr      %l4, %asr18
404 !       ld      [%sp + (24 + 84) * 4], %l4      ! can't write asr19
405 !       wr      %l4, %asr19
406 !       ld      [%sp + (24 + 85) * 4], %l4      ! can't write asr20
407 !       wr      %l4, %asr20
408 !       ld      [%sp + (24 + 86) * 4], %l4      ! can't write asr21
409 !       wr      %l4, %asr21
410         ld      [%sp + (24 + 87) * 4], %l4
411         wr      %l4, %asr22
412
413 ! End of restoring asr regs
414
415
416         ldd     [%sp + (24 + 64) * 4], %l0 ! Y & PSR
417         ldd     [%sp + (24 + 68) * 4], %l2 ! PC & NPC
418
419         restore                         ! Ensure that previous window is valid
420         save    %g0, %g0, %g0           !  by causing a window_underflow trap
421
422         mov     %l0, %y
423         mov     %l1, %psr               ! Make sure that traps are disabled
424                                         ! for rett
425         nop     ! 3 nops after write to %psr (needed?)
426         nop
427         nop
428
429         sethi   %hi(in_trap_handler), %l4
430         ld      [%lo(in_trap_handler) + %l4], %l5
431         dec     %l5
432         st      %l5, [%lo(in_trap_handler) + %l4]
433
434         jmpl    %l2, %g0                ! Restore old PC
435         rett    %l3                     ! Restore old nPC
436 ");
437
438 /* Convert ch from a hex digit to an int */
439
440 static int
441 hex(ch)
442      unsigned char ch;
443 {
444   if (ch >= 'a' && ch <= 'f')
445     return ch-'a'+10;
446   if (ch >= '0' && ch <= '9')
447     return ch-'0';
448   if (ch >= 'A' && ch <= 'F')
449     return ch-'A'+10;
450   return -1;
451 }
452
453 /* scan for the sequence $<data>#<checksum>     */
454
455 static void
456 getpacket(buffer)
457      char *buffer;
458 {
459   unsigned char checksum;
460   unsigned char xmitcsum;
461   int i;
462   int count;
463   unsigned char ch;
464
465   do
466     {
467       /* wait around for the start character, ignore all other characters */
468       while ((ch = (getDebugChar() & 0x7f)) != '$') 
469         ;
470
471       checksum = 0;
472       xmitcsum = -1;
473
474       count = 0;
475
476       /* now, read until a # or end of buffer is found */
477       while (count < BUFMAX)
478         {
479           ch = getDebugChar() & 0x7f;
480           if (ch == '#')
481             break;
482           checksum = checksum + ch;
483           buffer[count] = ch;
484           count = count + 1;
485         }
486
487       if (count >= BUFMAX)
488         continue;
489
490       buffer[count] = 0;
491
492       if (ch == '#')
493         {
494           xmitcsum = hex(ch = getDebugChar() & 0x7f) << 4;
495           xmitcsum |= hex(ch = getDebugChar() & 0x7f);
496
497           if (checksum != xmitcsum)
498             putDebugChar('-');  /* failed checksum */
499           else
500             {
501               putDebugChar('+'); /* successful transfer */
502               /* if a sequence char is present, reply the sequence ID */
503               if (buffer[2] == ':')
504                 {
505                   putDebugChar(buffer[0]);
506                   putDebugChar(buffer[1]);
507                   /* remove sequence chars from buffer */
508                   count = strlen(buffer);
509                   for (i=3; i <= count; i++)
510                     buffer[i-3] = buffer[i];
511                 }
512             }
513         }
514     }
515   while (checksum != xmitcsum);
516 }
517
518 /* send the packet in buffer.  */
519
520 static void
521 putpacket(buffer)
522      unsigned char *buffer;
523 {
524   unsigned char checksum;
525   int count;
526   unsigned char ch;
527
528   /*  $<packet info>#<checksum>. */
529   do
530     {
531       putDebugChar('$');
532       checksum = 0;
533       count = 0;
534
535       while (ch = buffer[count])
536         {
537           putDebugChar(ch);
538           checksum += ch;
539           count += 1;
540         }
541
542       putDebugChar('#');
543       putDebugChar(hexchars[checksum >> 4]);
544       putDebugChar(hexchars[checksum & 0xf]);
545
546     }
547   while ((getDebugChar() & 0x7f) != '+');
548 }
549
550 static char remcomInBuffer[BUFMAX];
551 static char remcomOutBuffer[BUFMAX];
552
553 /* Indicate to caller of mem2hex or hex2mem that there has been an
554    error.  */
555 static volatile int mem_err = 0;
556
557 /* Convert the memory pointed to by mem into hex, placing result in buf.
558  * Return a pointer to the last char put in buf (null), in case of mem fault,
559  * return 0.
560  * If MAY_FAULT is non-zero, then we will handle memory faults by returning
561  * a 0, else treat a fault like any other fault in the stub.
562  */
563
564 static unsigned char *
565 mem2hex(mem, buf, count, may_fault)
566      unsigned char *mem;
567      unsigned char *buf;
568      int count;
569      int may_fault;
570 {
571   unsigned char ch;
572
573   set_mem_fault_trap(may_fault);
574
575   while (count-- > 0)
576     {
577       ch = *mem++;
578       if (mem_err)
579         return 0;
580       *buf++ = hexchars[ch >> 4];
581       *buf++ = hexchars[ch & 0xf];
582     }
583
584   *buf = 0;
585
586   set_mem_fault_trap(0);
587
588   return buf;
589 }
590
591 /* convert the hex array pointed to by buf into binary to be placed in mem
592  * return a pointer to the character AFTER the last byte written */
593
594 static char *
595 hex2mem(buf, mem, count, may_fault)
596      unsigned char *buf;
597      unsigned char *mem;
598      int count;
599      int may_fault;
600 {
601   int i;
602   unsigned char ch;
603
604   set_mem_fault_trap(may_fault);
605
606   for (i=0; i<count; i++)
607     {
608       ch = hex(*buf++) << 4;
609       ch |= hex(*buf++);
610       *mem++ = ch;
611       if (mem_err)
612         return 0;
613     }
614
615   set_mem_fault_trap(0);
616
617   return mem;
618 }
619
620 /* This table contains the mapping between SPARC hardware trap types, and
621    signals, which are primarily what GDB understands.  It also indicates
622    which hardware traps we need to commandeer when initializing the stub. */
623
624 static struct hard_trap_info
625 {
626   unsigned char tt;             /* Trap type code for SPARClite */
627   unsigned char signo;          /* Signal that we map this trap into */
628 } hard_trap_info[] = {
629   {1, SIGSEGV},                 /* instruction access exception */
630   {0x3b, SIGSEGV},              /* instruction access error */
631   {2, SIGILL},                  /* illegal    instruction */
632   {3, SIGILL},                  /* privileged instruction */
633   {4, SIGEMT},                  /* fp disabled */
634   {0x24, SIGEMT},               /* cp disabled */
635   {7, SIGBUS},                  /* mem address not aligned */
636   {0x29, SIGSEGV},              /* data access exception */
637   {10, SIGEMT},                 /* tag overflow */
638   {128+1, SIGTRAP},             /* ta 1 - normal breakpoint instruction */
639   {0, 0}                        /* Must be last */
640 };
641
642 /* Set up exception handlers for tracing and breakpoints */
643
644 void
645 set_debug_traps()
646 {
647   struct hard_trap_info *ht;
648
649   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
650     exceptionHandler(ht->tt, trap_low);
651
652   /* In case GDB is started before us, ack any packets (presumably
653      "$?#xx") sitting there.  */
654   putDebugChar ('+');
655
656   initialized = 1;
657 }
658
659 asm ("
660 ! Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
661 ! assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
662 ! 0 would ever contain code that could mem fault.  This routine will skip
663 ! past the faulting instruction after setting mem_err.
664
665         .text
666         .align 4
667
668 _fltr_set_mem_err:
669         sethi %hi(_mem_err), %l0
670         st %l1, [%l0 + %lo(_mem_err)]
671         jmpl %l2, %g0
672         rett %l2+4
673 ");
674
675 static void
676 set_mem_fault_trap(enable)
677      int enable;
678 {
679   extern void fltr_set_mem_err();
680   mem_err = 0;
681
682   if (enable)
683     exceptionHandler(0x29, fltr_set_mem_err);
684   else
685     exceptionHandler(0x29, trap_low);
686 }
687
688 asm ("
689         .text
690         .align 4
691
692 _dummy_hw_breakpoint:
693         jmpl %l2, %g0
694         rett %l2+4
695         nop
696         nop
697 ");
698
699 static void
700 set_hw_breakpoint_trap(enable)
701      int enable;
702 {
703   extern void dummy_hw_breakpoint();
704
705   if (enable)
706     exceptionHandler(255, dummy_hw_breakpoint);
707   else
708     exceptionHandler(255, trap_low);
709 }
710
711 static void
712 get_in_break_mode()
713 {
714 #if 0
715   int x;
716   mesg("get_in_break_mode, sp = ");
717   phex(&x);
718 #endif
719   set_hw_breakpoint_trap(1);
720
721   asm("
722         sethi   %hi(0xff10), %l4
723         or      %l4, %lo(0xff10), %l4
724         sta     %g0, [%l4]0x1   
725         nop
726         nop
727         nop
728       ");
729
730   set_hw_breakpoint_trap(0);
731 }
732
733 /* Convert the SPARC hardware trap type code to a unix signal number. */
734
735 static int
736 computeSignal(tt)
737      int tt;
738 {
739   struct hard_trap_info *ht;
740
741   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
742     if (ht->tt == tt)
743       return ht->signo;
744
745   return SIGHUP;                /* default for things we don't know about */
746 }
747
748 /*
749  * While we find nice hex chars, build an int.
750  * Return number of chars processed.
751  */
752
753 static int
754 hexToInt(char **ptr, int *intValue)
755 {
756   int numChars = 0;
757   int hexValue;
758
759   *intValue = 0;
760
761   while (**ptr)
762     {
763       hexValue = hex(**ptr);
764       if (hexValue < 0)
765         break;
766
767       *intValue = (*intValue << 4) | hexValue;
768       numChars ++;
769
770       (*ptr)++;
771     }
772
773   return (numChars);
774 }
775
776 /*
777  * This function does all command procesing for interfacing to gdb.  It
778  * returns 1 if you should skip the instruction at the trap address, 0
779  * otherwise.
780  */
781
782 static void
783 handle_exception (registers)
784      unsigned long *registers;
785 {
786   int tt;                       /* Trap type */
787   int sigval;
788   int addr;
789   int length;
790   char *ptr;
791   unsigned long *sp;
792   unsigned long dsr;
793
794 /* First, we must force all of the windows to be spilled out */
795
796   asm("
797         ! Ugh.  sparclet has broken save
798         !save %sp, -64, %sp
799         save
800         add %fp,-64,%sp
801         !save %sp, -64, %sp
802         save
803         add %fp,-64,%sp
804         !save %sp, -64, %sp
805         save
806         add %fp,-64,%sp
807         !save %sp, -64, %sp
808         save
809         add %fp,-64,%sp
810         !save %sp, -64, %sp
811         save
812         add %fp,-64,%sp
813         !save %sp, -64, %sp
814         save
815         add %fp,-64,%sp
816         !save %sp, -64, %sp
817         save
818         add %fp,-64,%sp
819         !save %sp, -64, %sp
820         save
821         add %fp,-64,%sp
822         restore
823         restore
824         restore
825         restore
826         restore
827         restore
828         restore
829         restore
830 ");
831
832   if (registers[PC] == (unsigned long)breakinst)
833     {
834       registers[PC] = registers[NPC];
835       registers[NPC] += 4;
836     }
837   sp = (unsigned long *)registers[SP];
838
839   tt = (registers[TBR] >> 4) & 0xff;
840
841   /* reply to host that an exception has occurred */
842   sigval = computeSignal(tt);
843   ptr = remcomOutBuffer;
844
845   *ptr++ = 'T';
846   *ptr++ = hexchars[sigval >> 4];
847   *ptr++ = hexchars[sigval & 0xf];
848
849   *ptr++ = hexchars[PC >> 4];
850   *ptr++ = hexchars[PC & 0xf];
851   *ptr++ = ':';
852   ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
853   *ptr++ = ';';
854
855   *ptr++ = hexchars[FP >> 4];
856   *ptr++ = hexchars[FP & 0xf];
857   *ptr++ = ':';
858   ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
859   *ptr++ = ';';
860
861   *ptr++ = hexchars[SP >> 4];
862   *ptr++ = hexchars[SP & 0xf];
863   *ptr++ = ':';
864   ptr = mem2hex((char *)&sp, ptr, 4, 0);
865   *ptr++ = ';';
866
867   *ptr++ = hexchars[NPC >> 4];
868   *ptr++ = hexchars[NPC & 0xf];
869   *ptr++ = ':';
870   ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
871   *ptr++ = ';';
872
873   *ptr++ = hexchars[O7 >> 4];
874   *ptr++ = hexchars[O7 & 0xf];
875   *ptr++ = ':';
876   ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
877   *ptr++ = ';';
878
879   *ptr++ = 0;
880
881   putpacket(remcomOutBuffer);
882
883   while (1)
884     {
885       remcomOutBuffer[0] = 0;
886
887       getpacket(remcomInBuffer);
888       switch (remcomInBuffer[0])
889         {
890         case '?':
891           remcomOutBuffer[0] = 'S';
892           remcomOutBuffer[1] = hexchars[sigval >> 4];
893           remcomOutBuffer[2] = hexchars[sigval & 0xf];
894           remcomOutBuffer[3] = 0;
895           break;
896
897         case 'd':
898           remote_debug = !(remote_debug);       /* toggle debug flag */
899           break;
900
901         case 'g':               /* return the value of the CPU registers */
902           {
903             ptr = remcomOutBuffer;
904             ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
905             ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
906             memset(ptr, '0', 32 * 8); /* Floating point */
907             ptr = mem2hex((char *)&registers[Y],
908                     ptr + 32 * 4 * 2,
909                     8 * 4,
910                     0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
911             ptr = mem2hex((char *)&registers[CCSR],
912                     ptr,
913                     8 * 4,
914                     0); /* CCSR, CCPR, CCCRCR, CCOR, CCOBR, CCIBR, CCIR */
915             ptr = mem2hex((char *)&registers[ASR1],
916                     ptr,
917                     8 * 4,
918                     0); /* ASR1,ASR15,ASR17,ASR18,ASR19,ASR20,ASR21,ASR22 */
919 #if 0 /* not implemented */
920             ptr = mem2hex((char *) &registers[AWR0], 
921                     ptr, 
922                     32 * 4, 
923                     0); /* Alternate Window Registers */
924 #endif
925           }
926           break;
927
928         case 'G':       /* set value of all the CPU registers - return OK */
929         case 'P':       /* set value of one CPU register      - return OK */
930           {
931             unsigned long *newsp, psr;
932
933             psr = registers[PSR];
934
935             ptr = &remcomInBuffer[1];
936
937             if (remcomInBuffer[0] == 'P')       /* do a single register */
938               {
939                 int regno;
940  
941                 if (hexToInt (&ptr, &regno)
942                     && *ptr++ == '=')
943                   if (regno >= L0 && regno <= I7)
944                     hex2mem (ptr, sp + regno - L0, 4, 0);
945                   else
946                     hex2mem (ptr, (char *)&registers[regno], 4, 0);
947                 else
948                   {
949                     strcpy (remcomOutBuffer, "P01");
950                     break;
951                   }
952               }
953             else
954               {
955                 hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
956                 hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
957                 hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y],
958                         8 * 4, 0); /* Y,PSR,WIM,TBR,PC,NPC,FPSR,CPSR */
959                 hex2mem(ptr + 72 * 4 * 2, (char *)&registers[CCSR],
960                         8 * 4, 0); /* CCSR,CCPR,CCCRCR,CCOR,CCOBR,CCIBR,CCIR */
961                 hex2mem(ptr + 80 * 4 * 2, (char *)&registers[ASR1],
962                         8 * 4, 0); /* ASR1 ... ASR22 */
963 #if 0 /* not implemented */
964                 hex2mem(ptr + 88 * 4 * 2, (char *)&registers[AWR0],
965                         8 * 4, 0); /* Alternate Window Registers */
966 #endif
967               }
968             /* See if the stack pointer has moved.  If so, then copy the saved
969                locals and ins to the new location.  This keeps the window
970                overflow and underflow routines happy.  */
971
972             newsp = (unsigned long *)registers[SP];
973             if (sp != newsp)
974               sp = memcpy(newsp, sp, 16 * 4);
975
976             /* Don't allow CWP to be modified. */
977
978             if (psr != registers[PSR])
979               registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
980
981             strcpy(remcomOutBuffer,"OK");
982           }
983           break;
984
985         case 'm':         /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
986           /* Try to read %x,%x.  */
987
988           ptr = &remcomInBuffer[1];
989
990           if (hexToInt(&ptr, &addr)
991               && *ptr++ == ','
992               && hexToInt(&ptr, &length))
993             {
994               if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
995                 break;
996
997               strcpy (remcomOutBuffer, "E03");
998             }
999           else
1000             strcpy(remcomOutBuffer,"E01");
1001           break;
1002
1003         case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1004           /* Try to read '%x,%x:'.  */
1005
1006           ptr = &remcomInBuffer[1];
1007
1008           if (hexToInt(&ptr, &addr)
1009               && *ptr++ == ','
1010               && hexToInt(&ptr, &length)
1011               && *ptr++ == ':')
1012             {
1013               if (hex2mem(ptr, (char *)addr, length, 1))
1014                 strcpy(remcomOutBuffer, "OK");
1015               else
1016                 strcpy(remcomOutBuffer, "E03");
1017             }
1018           else
1019             strcpy(remcomOutBuffer, "E02");
1020           break;
1021
1022         case 'c':    /* cAA..AA    Continue at address AA..AA(optional) */
1023           /* try to read optional parameter, pc unchanged if no parm */
1024
1025           ptr = &remcomInBuffer[1];
1026           if (hexToInt(&ptr, &addr))
1027             {
1028               registers[PC] = addr;
1029               registers[NPC] = addr + 4;
1030             }
1031
1032 /* Need to flush the instruction cache here, as we may have deposited a
1033    breakpoint, and the icache probably has no way of knowing that a data ref to
1034    some location may have changed something that is in the instruction cache.
1035  */
1036
1037           flush_i_cache();
1038           return;
1039
1040           /* kill the program */
1041         case 'k' :              /* do nothing */
1042           break;
1043 #if 0
1044         case 't':               /* Test feature */
1045           asm (" std %f30,[%sp]");
1046           break;
1047 #endif
1048         case 'r':               /* Reset */
1049           asm ("call 0
1050                 nop ");
1051           break;
1052
1053 #if 0
1054 Disabled until we can unscrew this properly
1055
1056         case 'b':         /* bBB...  Set baud rate to BB... */
1057           {
1058             int baudrate;
1059             extern void set_timer_3();
1060
1061             ptr = &remcomInBuffer[1];
1062             if (!hexToInt(&ptr, &baudrate))
1063               {
1064                 strcpy(remcomOutBuffer,"B01");
1065                 break;
1066               }
1067
1068             /* Convert baud rate to uart clock divider */
1069             switch (baudrate)
1070               {
1071               case 38400:
1072                 baudrate = 16;
1073                 break;
1074               case 19200:
1075                 baudrate = 33;
1076                 break;
1077               case 9600:
1078                 baudrate = 65;
1079                 break;
1080               default:
1081                 strcpy(remcomOutBuffer,"B02");
1082                 goto x1;
1083               }
1084
1085             putpacket("OK");    /* Ack before changing speed */
1086             set_timer_3(baudrate); /* Set it */
1087           }
1088 x1:       break;
1089 #endif
1090         }                       /* switch */
1091
1092       /* reply to the request */
1093       putpacket(remcomOutBuffer);
1094     }
1095 }
1096
1097 /* This function will generate a breakpoint exception.  It is used at the
1098    beginning of a program to sync up with a debugger and can be used
1099    otherwise as a quick means to stop program execution and "break" into
1100    the debugger. */
1101
1102 void
1103 breakpoint()
1104 {
1105   if (!initialized)
1106     return;
1107
1108   asm(" .globl _breakinst
1109
1110         _breakinst: ta 1
1111       ");
1112 }
1113
1114 static void
1115 hw_breakpoint()
1116 {
1117   asm("
1118       ta 127
1119       ");
1120 }
1121
1122 #if 0 /* experimental and never finished, left here for reference */
1123 static void
1124 splet_temp(void)
1125 {
1126   asm(" sub     %sp,(16+1+6+1+121)*4,%sp ! Make room for input & locals
1127                                         ! + hidden arg + arg spill
1128                                         ! + doubleword alignment
1129                                         ! + registers[121]
1130
1131 ! Leave a trail of breadcrumbs! (save register save area for debugging)
1132         mov     %sp, %l0
1133         add     %l0, 24*4, %l0
1134         sethi   %hi(_debug_registers), %l1
1135         st      %l0, [%lo(_debug_registers) + %l1]
1136
1137 ! Save the Alternate Register Set: (not implemented yet)
1138 !    To save the Alternate Register set, we must:
1139 !    1) Save the current SP in some global location.
1140 !    2) Swap the register sets.
1141 !    3) Save the Alternate SP in the Y register
1142 !    4) Fetch the SP that we saved in step 1.
1143 !    5) Use that to save the rest of the regs (not forgetting ASP in Y)
1144 !    6) Restore the Alternate SP from Y
1145 !    7) Swap the registers back.
1146
1147 ! 1) Copy the current stack pointer to global _SAVED_STACK_POINTER:
1148         sethi   %hi(_saved_stack_pointer), %l0
1149         st      %sp, [%lo(_saved_stack_pointer) + %l0]
1150
1151 ! 2) Swap the register sets:
1152         mov     %psr, %l1
1153         sethi   %hi(0x10000), %l2
1154         xor     %l1, %l2, %l1
1155         mov     %l1, %psr
1156         nop                     ! 3 nops after write to %psr (needed?)
1157         nop
1158         nop
1159
1160 ! 3) Save Alternate L0 in Y
1161         wr      %l0, 0, %y
1162
1163 ! 4) Load former SP into alternate SP, using L0
1164         sethi   %hi(_saved_stack_pointer), %l0
1165         or      %lo(_saved_stack_pointer), %l0, %l0
1166         swap    [%l0], %sp
1167
1168 ! 4.5) Restore alternate L0
1169         rd      %y, %l0
1170
1171 ! 5) Save the Alternate Window Registers
1172         st      %r0, [%sp + (24 + 88) * 4]      ! AWR0
1173         st      %r1, [%sp + (24 + 89) * 4]      ! AWR1
1174         st      %r2, [%sp + (24 + 90) * 4]      ! AWR2
1175         st      %r3, [%sp + (24 + 91) * 4]      ! AWR3
1176         st      %r4, [%sp + (24 + 92) * 4]      ! AWR4
1177         st      %r5, [%sp + (24 + 93) * 4]      ! AWR5
1178         st      %r6, [%sp + (24 + 94) * 4]      ! AWR6
1179         st      %r7, [%sp + (24 + 95) * 4]      ! AWR7
1180         st      %r8, [%sp + (24 + 96) * 4]      ! AWR8
1181         st      %r9, [%sp + (24 + 97) * 4]      ! AWR9
1182         st      %r10, [%sp + (24 + 98) * 4]     ! AWR10
1183         st      %r11, [%sp + (24 + 99) * 4]     ! AWR11
1184         st      %r12, [%sp + (24 + 100) * 4]    ! AWR12
1185         st      %r13, [%sp + (24 + 101) * 4]    ! AWR13
1186 !       st      %r14, [%sp + (24 + 102) * 4]    ! AWR14 (SP)
1187         st      %r15, [%sp + (24 + 103) * 4]    ! AWR15
1188         st      %r16, [%sp + (24 + 104) * 4]    ! AWR16
1189         st      %r17, [%sp + (24 + 105) * 4]    ! AWR17
1190         st      %r18, [%sp + (24 + 106) * 4]    ! AWR18
1191         st      %r19, [%sp + (24 + 107) * 4]    ! AWR19
1192         st      %r20, [%sp + (24 + 108) * 4]    ! AWR20
1193         st      %r21, [%sp + (24 + 109) * 4]    ! AWR21
1194         st      %r22, [%sp + (24 + 110) * 4]    ! AWR22
1195         st      %r23, [%sp + (24 + 111) * 4]    ! AWR23
1196         st      %r24, [%sp + (24 + 112) * 4]    ! AWR24
1197         st      %r25, [%sp + (24 + 113) * 4]    ! AWR25
1198         st      %r26, [%sp + (24 + 114) * 4]    ! AWR26
1199         st      %r27, [%sp + (24 + 115) * 4]    ! AWR27
1200         st      %r28, [%sp + (24 + 116) * 4]    ! AWR28
1201         st      %r29, [%sp + (24 + 117) * 4]    ! AWR29
1202         st      %r30, [%sp + (24 + 118) * 4]    ! AWR30
1203         st      %r31, [%sp + (24 + 119) * 4]    ! AWR21
1204
1205 ! Get the Alternate PSR (I hope...)
1206
1207         rd      %psr, %l2
1208         st      %l2, [%sp + (24 + 120) * 4]     ! APSR
1209
1210 ! Don't forget the alternate stack pointer
1211
1212         rd      %y, %l3
1213         st      %l3, [%sp + (24 + 102) * 4]     ! AWR14 (SP)
1214
1215 ! 6) Restore the Alternate SP (saved in Y)
1216
1217         rd      %y, %o6
1218
1219
1220 ! 7) Swap the registers back:
1221
1222         mov     %psr, %l1
1223         sethi   %hi(0x10000), %l2
1224         xor     %l1, %l2, %l1
1225         mov     %l1, %psr
1226         nop                     ! 3 nops after write to %psr (needed?)
1227         nop
1228         nop
1229 ");
1230 }
1231
1232 #endif