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