OSDN Git Service

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