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