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