OSDN Git Service

2009-10-08 Jie Zhang <jie.zhang@analog.com>
[pf3gnuchains/sourceware.git] / libgloss / sparc / 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 putDebugChar();   /* write a single character      */
99 extern 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           if (! putDebugChar(ch))
538             return;
539           checksum += ch;
540           count += 1;
541         }
542
543       putDebugChar('#');
544       putDebugChar(hexchars[checksum >> 4]);
545       putDebugChar(hexchars[checksum & 0xf]);
546
547     }
548   while ((getDebugChar() & 0x7f) != '+');
549 }
550
551 static char remcomInBuffer[BUFMAX];
552 static char remcomOutBuffer[BUFMAX];
553
554 /* Indicate to caller of mem2hex or hex2mem that there has been an
555    error.  */
556 static volatile int mem_err = 0;
557
558 /* Convert the memory pointed to by mem into hex, placing result in buf.
559  * Return a pointer to the last char put in buf (null), in case of mem fault,
560  * return 0.
561  * If MAY_FAULT is non-zero, then we will handle memory faults by returning
562  * a 0, else treat a fault like any other fault in the stub.
563  */
564
565 static unsigned char *
566 mem2hex(mem, buf, count, may_fault)
567      unsigned char *mem;
568      unsigned char *buf;
569      int count;
570      int may_fault;
571 {
572   unsigned char ch;
573
574   set_mem_fault_trap(may_fault);
575
576   while (count-- > 0)
577     {
578       ch = *mem++;
579       if (mem_err)
580         return 0;
581       *buf++ = hexchars[ch >> 4];
582       *buf++ = hexchars[ch & 0xf];
583     }
584
585   *buf = 0;
586
587   set_mem_fault_trap(0);
588
589   return buf;
590 }
591
592 /* convert the hex array pointed to by buf into binary to be placed in mem
593  * return a pointer to the character AFTER the last byte written */
594
595 static char *
596 hex2mem(buf, mem, count, may_fault)
597      unsigned char *buf;
598      unsigned char *mem;
599      int count;
600      int may_fault;
601 {
602   int i;
603   unsigned char ch;
604
605   set_mem_fault_trap(may_fault);
606
607   for (i=0; i<count; i++)
608     {
609       ch = hex(*buf++) << 4;
610       ch |= hex(*buf++);
611       *mem++ = ch;
612       if (mem_err)
613         return 0;
614     }
615
616   set_mem_fault_trap(0);
617
618   return mem;
619 }
620
621 /* This table contains the mapping between SPARC hardware trap types, and
622    signals, which are primarily what GDB understands.  It also indicates
623    which hardware traps we need to commandeer when initializing the stub. */
624
625 static struct hard_trap_info
626 {
627   unsigned char tt;             /* Trap type code for SPARClite */
628   unsigned char signo;          /* Signal that we map this trap into */
629 } hard_trap_info[] = {
630   {1, SIGSEGV},                 /* instruction access exception */
631   {0x3b, SIGSEGV},              /* instruction access error */
632   {2, SIGILL},                  /* illegal    instruction */
633   {3, SIGILL},                  /* privileged instruction */
634   {4, SIGEMT},                  /* fp disabled */
635   {0x24, SIGEMT},               /* cp disabled */
636   {7, SIGBUS},                  /* mem address not aligned */
637   {0x29, SIGSEGV},              /* data access exception */
638   {10, SIGEMT},                 /* tag overflow */
639   {128+1, SIGTRAP},             /* ta 1 - normal breakpoint instruction */
640   {0, 0}                        /* Must be last */
641 };
642
643 /* Set up exception handlers for tracing and breakpoints */
644
645 void
646 set_debug_traps()
647 {
648   struct hard_trap_info *ht;
649
650   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
651     exceptionHandler(ht->tt, trap_low);
652
653   /* In case GDB is started before us, ack any packets (presumably
654      "$?#xx") sitting there.  */
655   putDebugChar ('+');
656
657   initialized = 1;
658 }
659
660 asm ("
661 ! Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
662 ! assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
663 ! 0 would ever contain code that could mem fault.  This routine will skip
664 ! past the faulting instruction after setting mem_err.
665
666         .text
667         .align 4
668
669 _fltr_set_mem_err:
670         sethi %hi(_mem_err), %l0
671         st %l1, [%l0 + %lo(_mem_err)]
672         jmpl %l2, %g0
673         rett %l2+4
674 ");
675
676 static void
677 set_mem_fault_trap(enable)
678      int enable;
679 {
680   extern void fltr_set_mem_err();
681   mem_err = 0;
682
683   if (enable)
684     exceptionHandler(0x29, fltr_set_mem_err);
685   else
686     exceptionHandler(0x29, trap_low);
687 }
688
689 asm ("
690         .text
691         .align 4
692
693 _dummy_hw_breakpoint:
694         jmpl %l2, %g0
695         rett %l2+4
696         nop
697         nop
698 ");
699
700 static void
701 set_hw_breakpoint_trap(enable)
702      int enable;
703 {
704   extern void dummy_hw_breakpoint();
705
706   if (enable)
707     exceptionHandler(255, dummy_hw_breakpoint);
708   else
709     exceptionHandler(255, trap_low);
710 }
711
712 static void
713 get_in_break_mode()
714 {
715 #if 0
716   int x;
717   mesg("get_in_break_mode, sp = ");
718   phex(&x);
719 #endif
720   set_hw_breakpoint_trap(1);
721
722   asm("
723         sethi   %hi(0xff10), %l4
724         or      %l4, %lo(0xff10), %l4
725         sta     %g0, [%l4]0x1   
726         nop
727         nop
728         nop
729       ");
730
731   set_hw_breakpoint_trap(0);
732 }
733
734 /* Convert the SPARC hardware trap type code to a unix signal number. */
735
736 static int
737 computeSignal(tt)
738      int tt;
739 {
740   struct hard_trap_info *ht;
741
742   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
743     if (ht->tt == tt)
744       return ht->signo;
745
746   return SIGHUP;                /* default for things we don't know about */
747 }
748
749 /*
750  * While we find nice hex chars, build an int.
751  * Return number of chars processed.
752  */
753
754 static int
755 hexToInt(char **ptr, int *intValue)
756 {
757   int numChars = 0;
758   int hexValue;
759
760   *intValue = 0;
761
762   while (**ptr)
763     {
764       hexValue = hex(**ptr);
765       if (hexValue < 0)
766         break;
767
768       *intValue = (*intValue << 4) | hexValue;
769       numChars ++;
770
771       (*ptr)++;
772     }
773
774   return (numChars);
775 }
776
777 /*
778  * This function does all command procesing for interfacing to gdb.  It
779  * returns 1 if you should skip the instruction at the trap address, 0
780  * otherwise.
781  */
782
783 static void
784 handle_exception (registers)
785      unsigned long *registers;
786 {
787   int tt;                       /* Trap type */
788   int sigval;
789   int addr;
790   int length;
791   char *ptr;
792   unsigned long *sp;
793   unsigned long dsr;
794
795 /* First, we must force all of the windows to be spilled out */
796
797   asm("
798         ! Ugh.  sparclet has broken save
799         !save %sp, -64, %sp
800         save
801         add %fp,-64,%sp
802         !save %sp, -64, %sp
803         save
804         add %fp,-64,%sp
805         !save %sp, -64, %sp
806         save
807         add %fp,-64,%sp
808         !save %sp, -64, %sp
809         save
810         add %fp,-64,%sp
811         !save %sp, -64, %sp
812         save
813         add %fp,-64,%sp
814         !save %sp, -64, %sp
815         save
816         add %fp,-64,%sp
817         !save %sp, -64, %sp
818         save
819         add %fp,-64,%sp
820         !save %sp, -64, %sp
821         save
822         add %fp,-64,%sp
823         restore
824         restore
825         restore
826         restore
827         restore
828         restore
829         restore
830         restore
831 ");
832
833   if (registers[PC] == (unsigned long)breakinst)
834     {
835       registers[PC] = registers[NPC];
836       registers[NPC] += 4;
837     }
838   sp = (unsigned long *)registers[SP];
839
840   tt = (registers[TBR] >> 4) & 0xff;
841
842   /* reply to host that an exception has occurred */
843   sigval = computeSignal(tt);
844   ptr = remcomOutBuffer;
845
846   *ptr++ = 'T';
847   *ptr++ = hexchars[sigval >> 4];
848   *ptr++ = hexchars[sigval & 0xf];
849
850   *ptr++ = hexchars[PC >> 4];
851   *ptr++ = hexchars[PC & 0xf];
852   *ptr++ = ':';
853   ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
854   *ptr++ = ';';
855
856   *ptr++ = hexchars[FP >> 4];
857   *ptr++ = hexchars[FP & 0xf];
858   *ptr++ = ':';
859   ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
860   *ptr++ = ';';
861
862   *ptr++ = hexchars[SP >> 4];
863   *ptr++ = hexchars[SP & 0xf];
864   *ptr++ = ':';
865   ptr = mem2hex((char *)&sp, ptr, 4, 0);
866   *ptr++ = ';';
867
868   *ptr++ = hexchars[NPC >> 4];
869   *ptr++ = hexchars[NPC & 0xf];
870   *ptr++ = ':';
871   ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
872   *ptr++ = ';';
873
874   *ptr++ = hexchars[O7 >> 4];
875   *ptr++ = hexchars[O7 & 0xf];
876   *ptr++ = ':';
877   ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
878   *ptr++ = ';';
879
880   *ptr++ = 0;
881
882   putpacket(remcomOutBuffer);
883
884   while (1)
885     {
886       remcomOutBuffer[0] = 0;
887
888       getpacket(remcomInBuffer);
889       switch (remcomInBuffer[0])
890         {
891         case '?':
892           remcomOutBuffer[0] = 'S';
893           remcomOutBuffer[1] = hexchars[sigval >> 4];
894           remcomOutBuffer[2] = hexchars[sigval & 0xf];
895           remcomOutBuffer[3] = 0;
896           break;
897
898         case 'd':
899           remote_debug = !(remote_debug);       /* toggle debug flag */
900           break;
901
902         case 'g':               /* return the value of the CPU registers */
903           {
904             ptr = remcomOutBuffer;
905             ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
906             ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
907             memset(ptr, '0', 32 * 8); /* Floating point */
908             ptr = mem2hex((char *)&registers[Y],
909                     ptr + 32 * 4 * 2,
910                     8 * 4,
911                     0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
912             ptr = mem2hex((char *)&registers[CCSR],
913                     ptr,
914                     8 * 4,
915                     0); /* CCSR, CCPR, CCCRCR, CCOR, CCOBR, CCIBR, CCIR */
916             ptr = mem2hex((char *)&registers[ASR1],
917                     ptr,
918                     8 * 4,
919                     0); /* ASR1,ASR15,ASR17,ASR18,ASR19,ASR20,ASR21,ASR22 */
920 #if 0 /* not implemented */
921             ptr = mem2hex((char *) &registers[AWR0], 
922                     ptr, 
923                     32 * 4, 
924                     0); /* Alternate Window Registers */
925 #endif
926           }
927           break;
928
929         case 'G':       /* set value of all the CPU registers - return OK */
930         case 'P':       /* set value of one CPU register      - return OK */
931           {
932             unsigned long *newsp, psr;
933
934             psr = registers[PSR];
935
936             ptr = &remcomInBuffer[1];
937
938             if (remcomInBuffer[0] == 'P')       /* do a single register */
939               {
940                 int regno;
941  
942                 if (hexToInt (&ptr, &regno)
943                     && *ptr++ == '=')
944                   if (regno >= L0 && regno <= I7)
945                     hex2mem (ptr, sp + regno - L0, 4, 0);
946                   else
947                     hex2mem (ptr, (char *)&registers[regno], 4, 0);
948                 else
949                   {
950                     strcpy (remcomOutBuffer, "P01");
951                     break;
952                   }
953               }
954             else
955               {
956                 hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
957                 hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
958                 hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y],
959                         8 * 4, 0); /* Y,PSR,WIM,TBR,PC,NPC,FPSR,CPSR */
960                 hex2mem(ptr + 72 * 4 * 2, (char *)&registers[CCSR],
961                         8 * 4, 0); /* CCSR,CCPR,CCCRCR,CCOR,CCOBR,CCIBR,CCIR */
962                 hex2mem(ptr + 80 * 4 * 2, (char *)&registers[ASR1],
963                         8 * 4, 0); /* ASR1 ... ASR22 */
964 #if 0 /* not implemented */
965                 hex2mem(ptr + 88 * 4 * 2, (char *)&registers[AWR0],
966                         8 * 4, 0); /* Alternate Window Registers */
967 #endif
968               }
969             /* See if the stack pointer has moved.  If so, then copy the saved
970                locals and ins to the new location.  This keeps the window
971                overflow and underflow routines happy.  */
972
973             newsp = (unsigned long *)registers[SP];
974             if (sp != newsp)
975               sp = memcpy(newsp, sp, 16 * 4);
976
977             /* Don't allow CWP to be modified. */
978
979             if (psr != registers[PSR])
980               registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
981
982             strcpy(remcomOutBuffer,"OK");
983           }
984           break;
985
986         case 'm':         /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
987           /* Try to read %x,%x.  */
988
989           ptr = &remcomInBuffer[1];
990
991           if (hexToInt(&ptr, &addr)
992               && *ptr++ == ','
993               && hexToInt(&ptr, &length))
994             {
995               if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
996                 break;
997
998               strcpy (remcomOutBuffer, "E03");
999             }
1000           else
1001             strcpy(remcomOutBuffer,"E01");
1002           break;
1003
1004         case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1005           /* Try to read '%x,%x:'.  */
1006
1007           ptr = &remcomInBuffer[1];
1008
1009           if (hexToInt(&ptr, &addr)
1010               && *ptr++ == ','
1011               && hexToInt(&ptr, &length)
1012               && *ptr++ == ':')
1013             {
1014               if (hex2mem(ptr, (char *)addr, length, 1))
1015                 strcpy(remcomOutBuffer, "OK");
1016               else
1017                 strcpy(remcomOutBuffer, "E03");
1018             }
1019           else
1020             strcpy(remcomOutBuffer, "E02");
1021           break;
1022
1023         case 'c':    /* cAA..AA    Continue at address AA..AA(optional) */
1024           /* try to read optional parameter, pc unchanged if no parm */
1025
1026           ptr = &remcomInBuffer[1];
1027           if (hexToInt(&ptr, &addr))
1028             {
1029               registers[PC] = addr;
1030               registers[NPC] = addr + 4;
1031             }
1032
1033 /* Need to flush the instruction cache here, as we may have deposited a
1034    breakpoint, and the icache probably has no way of knowing that a data ref to
1035    some location may have changed something that is in the instruction cache.
1036  */
1037
1038           flush_i_cache();
1039           return;
1040
1041           /* kill the program */
1042         case 'k' :              /* do nothing */
1043           break;
1044 #if 0
1045         case 't':               /* Test feature */
1046           asm (" std %f30,[%sp]");
1047           break;
1048 #endif
1049         case 'r':               /* Reset */
1050           asm ("call 0
1051                 nop ");
1052           break;
1053
1054 #if 0
1055 Disabled until we can unscrew this properly
1056
1057         case 'b':         /* bBB...  Set baud rate to BB... */
1058           {
1059             int baudrate;
1060             extern void set_timer_3();
1061
1062             ptr = &remcomInBuffer[1];
1063             if (!hexToInt(&ptr, &baudrate))
1064               {
1065                 strcpy(remcomOutBuffer,"B01");
1066                 break;
1067               }
1068
1069             /* Convert baud rate to uart clock divider */
1070             switch (baudrate)
1071               {
1072               case 38400:
1073                 baudrate = 16;
1074                 break;
1075               case 19200:
1076                 baudrate = 33;
1077                 break;
1078               case 9600:
1079                 baudrate = 65;
1080                 break;
1081               default:
1082                 strcpy(remcomOutBuffer,"B02");
1083                 goto x1;
1084               }
1085
1086             putpacket("OK");    /* Ack before changing speed */
1087             set_timer_3(baudrate); /* Set it */
1088           }
1089 x1:       break;
1090 #endif
1091         }                       /* switch */
1092
1093       /* reply to the request */
1094       putpacket(remcomOutBuffer);
1095     }
1096 }
1097
1098 /* This function will generate a breakpoint exception.  It is used at the
1099    beginning of a program to sync up with a debugger and can be used
1100    otherwise as a quick means to stop program execution and "break" into
1101    the debugger. */
1102
1103 void
1104 breakpoint()
1105 {
1106   if (!initialized)
1107     return;
1108
1109   asm(" .globl _breakinst
1110
1111         _breakinst: ta 1
1112       ");
1113 }
1114
1115 static void
1116 hw_breakpoint()
1117 {
1118   asm("
1119       ta 127
1120       ");
1121 }
1122
1123 #if 0 /* experimental and never finished, left here for reference */
1124 static void
1125 splet_temp(void)
1126 {
1127   asm(" sub     %sp,(16+1+6+1+121)*4,%sp ! Make room for input & locals
1128                                         ! + hidden arg + arg spill
1129                                         ! + doubleword alignment
1130                                         ! + registers[121]
1131
1132 ! Leave a trail of breadcrumbs! (save register save area for debugging)
1133         mov     %sp, %l0
1134         add     %l0, 24*4, %l0
1135         sethi   %hi(_debug_registers), %l1
1136         st      %l0, [%lo(_debug_registers) + %l1]
1137
1138 ! Save the Alternate Register Set: (not implemented yet)
1139 !    To save the Alternate Register set, we must:
1140 !    1) Save the current SP in some global location.
1141 !    2) Swap the register sets.
1142 !    3) Save the Alternate SP in the Y register
1143 !    4) Fetch the SP that we saved in step 1.
1144 !    5) Use that to save the rest of the regs (not forgetting ASP in Y)
1145 !    6) Restore the Alternate SP from Y
1146 !    7) Swap the registers back.
1147
1148 ! 1) Copy the current stack pointer to global _SAVED_STACK_POINTER:
1149         sethi   %hi(_saved_stack_pointer), %l0
1150         st      %sp, [%lo(_saved_stack_pointer) + %l0]
1151
1152 ! 2) Swap the register sets:
1153         mov     %psr, %l1
1154         sethi   %hi(0x10000), %l2
1155         xor     %l1, %l2, %l1
1156         mov     %l1, %psr
1157         nop                     ! 3 nops after write to %psr (needed?)
1158         nop
1159         nop
1160
1161 ! 3) Save Alternate L0 in Y
1162         wr      %l0, 0, %y
1163
1164 ! 4) Load former SP into alternate SP, using L0
1165         sethi   %hi(_saved_stack_pointer), %l0
1166         or      %lo(_saved_stack_pointer), %l0, %l0
1167         swap    [%l0], %sp
1168
1169 ! 4.5) Restore alternate L0
1170         rd      %y, %l0
1171
1172 ! 5) Save the Alternate Window Registers
1173         st      %r0, [%sp + (24 + 88) * 4]      ! AWR0
1174         st      %r1, [%sp + (24 + 89) * 4]      ! AWR1
1175         st      %r2, [%sp + (24 + 90) * 4]      ! AWR2
1176         st      %r3, [%sp + (24 + 91) * 4]      ! AWR3
1177         st      %r4, [%sp + (24 + 92) * 4]      ! AWR4
1178         st      %r5, [%sp + (24 + 93) * 4]      ! AWR5
1179         st      %r6, [%sp + (24 + 94) * 4]      ! AWR6
1180         st      %r7, [%sp + (24 + 95) * 4]      ! AWR7
1181         st      %r8, [%sp + (24 + 96) * 4]      ! AWR8
1182         st      %r9, [%sp + (24 + 97) * 4]      ! AWR9
1183         st      %r10, [%sp + (24 + 98) * 4]     ! AWR10
1184         st      %r11, [%sp + (24 + 99) * 4]     ! AWR11
1185         st      %r12, [%sp + (24 + 100) * 4]    ! AWR12
1186         st      %r13, [%sp + (24 + 101) * 4]    ! AWR13
1187 !       st      %r14, [%sp + (24 + 102) * 4]    ! AWR14 (SP)
1188         st      %r15, [%sp + (24 + 103) * 4]    ! AWR15
1189         st      %r16, [%sp + (24 + 104) * 4]    ! AWR16
1190         st      %r17, [%sp + (24 + 105) * 4]    ! AWR17
1191         st      %r18, [%sp + (24 + 106) * 4]    ! AWR18
1192         st      %r19, [%sp + (24 + 107) * 4]    ! AWR19
1193         st      %r20, [%sp + (24 + 108) * 4]    ! AWR20
1194         st      %r21, [%sp + (24 + 109) * 4]    ! AWR21
1195         st      %r22, [%sp + (24 + 110) * 4]    ! AWR22
1196         st      %r23, [%sp + (24 + 111) * 4]    ! AWR23
1197         st      %r24, [%sp + (24 + 112) * 4]    ! AWR24
1198         st      %r25, [%sp + (24 + 113) * 4]    ! AWR25
1199         st      %r26, [%sp + (24 + 114) * 4]    ! AWR26
1200         st      %r27, [%sp + (24 + 115) * 4]    ! AWR27
1201         st      %r28, [%sp + (24 + 116) * 4]    ! AWR28
1202         st      %r29, [%sp + (24 + 117) * 4]    ! AWR29
1203         st      %r30, [%sp + (24 + 118) * 4]    ! AWR30
1204         st      %r31, [%sp + (24 + 119) * 4]    ! AWR21
1205
1206 ! Get the Alternate PSR (I hope...)
1207
1208         rd      %psr, %l2
1209         st      %l2, [%sp + (24 + 120) * 4]     ! APSR
1210
1211 ! Don't forget the alternate stack pointer
1212
1213         rd      %y, %l3
1214         st      %l3, [%sp + (24 + 102) * 4]     ! AWR14 (SP)
1215
1216 ! 6) Restore the Alternate SP (saved in Y)
1217
1218         rd      %y, %o6
1219
1220
1221 ! 7) Swap the registers back:
1222
1223         mov     %psr, %l1
1224         sethi   %hi(0x10000), %l2
1225         xor     %l1, %l2, %l1
1226         mov     %l1, %psr
1227         nop                     ! 3 nops after write to %psr (needed?)
1228         nop
1229         nop
1230 ");
1231 }
1232
1233 #endif