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