* Contribute CGEN simulator build support code.
[binutils-gdb.git] / gdb / sparclet-stub.c
blobf593df7f7e349f34752f26622fe3ce312eb5a96b
1 /****************************************************************************
3 THIS SOFTWARE IS NOT COPYRIGHTED
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.
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.
13 ****************************************************************************/
15 /****************************************************************************
16 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
18 * Module name: remcom.c $
19 * Revision: 1.34 $
20 * Date: 91/03/09 12:29:49 $
21 * Contributor: Lake Stevens Instrument Division$
23 * Description: low level support for gdb debugger. $
25 * Considerations: only works on target hardware $
27 * Written by: Glenn Engel $
28 * ModuleState: Experimental $
30 * NOTES: See Below $
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.
36 * This code has been extensively tested on the Fujitsu SPARClite demo board.
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.
45 *************
47 * The following gdb commands are supported:
49 * command function Return value
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
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
58 * c Resume at current address SNN ( signal NN)
59 * cAA..AA Continue at address AA..AA SNN
61 * s Step one instruction SNN
62 * sAA..AA Step one instruction from AA..AA SNN
64 * k kill
66 * ? What was the last sigval ? SNN (signal NN)
68 * All commands and responses are sent with a packet which includes a
69 * checksum. A packet consists of
71 * $<packet info>#<checksum>.
73 * where
74 * <packet info> :: <characters representing the command or response>
75 * <checksum> :: <two hex digits computed as modulo 256 sum of <packetinfo>>
77 * When a packet is received, it is first acknowledged with either '+' or '-'.
78 * '+' indicates a successful transfer. '-' indicates a failed transfer.
80 * Example:
82 * Host: Reply:
83 * $m0,10#2a +$00010203040506070809101112131415#42
85 ****************************************************************************/
87 #include <string.h>
88 #include <signal.h>
90 /************************************************************************
92 * external low-level support routines
95 extern void putDebugChar(); /* write a single character */
96 extern int getDebugChar(); /* read and return a single char */
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
103 static int initialized = 0; /* !0 means we've been initialized */
104 static int remote_debug = 0; /* turn on verbose debugging */
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();
113 static const char hexchars[]="0123456789abcdef";
115 #define NUMREGS 121
117 static unsigned long saved_stack_pointer;
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,
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,
131 Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR,
132 CCSR, CCPR, CCCRCR, CCOR, CCOBR, CCIBR, CCIR, UNUSED1,
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
143 /*************************** ASSEMBLY CODE MACROS *************************/
144 /* */
146 extern void trap_low();
148 asm("
149 .reserve trapstack, 1000 * 4, \"bss\", 8
151 .data
152 .align 4
154 in_trap_handler:
155 .word 0
157 .text
158 .align 4
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.
165 ! On entry, trap_low expects l1 and l2 to contain pc and npc respectivly.
167 .globl _trap_low
168 _trap_low:
169 mov %psr, %l0
170 mov %wim, %l3
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
178 ! Handle window overflow
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
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.
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
202 mov 0x80, %g1 ! Hack for sparclet
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
213 good_wim:
214 save %g0, %g0, %g0 ! Slip into next window
215 mov %g1, %wim ! Install the new wim
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]
222 std %i0, [%sp + 8 * 4]
223 std %i2, [%sp + 10 * 4]
224 std %i4, [%sp + 12 * 4]
225 std %i6, [%sp + 14 * 4]
227 restore ! Go back to trap window.
228 mov %l4, %g1 ! Restore %g1
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
237 set trapstack+1000*4, %sp ! Switch to trap stack
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]
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]
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]
256 ! FP regs (sparclet doesn't have fpu)
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
273 ! Save coprocessor state.
274 ! See SK/demo/hdlc_demo/ldc_swap_context.S.
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?)
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?)
308 ! End of saving coprocessor state.
309 ! Save asr regs
311 ! Part of this is silly -- we should not display ASR15 or ASR19 at all.
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
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]
336 ! End of saving asr regs
338 call _handle_exception
339 add %sp, 24 * 4, %o0 ! Pass address of registers
341 ! Reload all of the registers that aren't on the stack
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
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
353 ! FP regs (sparclet doesn't have fpu)
355 ! Update the coprocessor registers.
356 ! See SK/demo/hdlc_demo/ldc_swap_context.S.
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?)
366 mov 0x6, %l2
367 cwrcxt %l2, %ccsr ! set CCP state machine for CCFR
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
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
385 mov %l0, %psr ! restore PSR
386 nop ! 3 nops after write to %psr (needed?)
390 ! End of coprocessor handling stuff.
391 ! Update asr regs
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
410 ! End of restoring asr regs
413 ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
414 ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
416 restore ! Ensure that previous window is valid
417 save %g0, %g0, %g0 ! by causing a window_underflow trap
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?)
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]
431 jmpl %l2, %g0 ! Restore old PC
432 rett %l3 ! Restore old nPC
435 /* Convert ch from a hex digit to an int */
437 static int
438 hex (unsigned char ch)
440 if (ch >= 'a' && ch <= 'f')
441 return ch-'a'+10;
442 if (ch >= '0' && ch <= '9')
443 return ch-'0';
444 if (ch >= 'A' && ch <= 'F')
445 return ch-'A'+10;
446 return -1;
449 static char remcomInBuffer[BUFMAX];
450 static char remcomOutBuffer[BUFMAX];
452 /* scan for the sequence $<data>#<checksum> */
454 unsigned char *
455 getpacket (void)
457 unsigned char *buffer = &remcomInBuffer[0];
458 unsigned char checksum;
459 unsigned char xmitcsum;
460 int count;
461 char ch;
463 while (1)
465 /* wait around for the start character, ignore all other characters */
466 while ((ch = getDebugChar ()) != '$')
469 retry:
470 checksum = 0;
471 xmitcsum = -1;
472 count = 0;
474 /* now, read until a # or end of buffer is found */
475 while (count < BUFMAX)
477 ch = getDebugChar ();
478 if (ch == '$')
479 goto retry;
480 if (ch == '#')
481 break;
482 checksum = checksum + ch;
483 buffer[count] = ch;
484 count = count + 1;
486 buffer[count] = 0;
488 if (ch == '#')
490 ch = getDebugChar ();
491 xmitcsum = hex (ch) << 4;
492 ch = getDebugChar ();
493 xmitcsum += hex (ch);
495 if (checksum != xmitcsum)
497 putDebugChar ('-'); /* failed checksum */
499 else
501 putDebugChar ('+'); /* successful transfer */
503 /* if a sequence char is present, reply the sequence ID */
504 if (buffer[2] == ':')
506 putDebugChar (buffer[0]);
507 putDebugChar (buffer[1]);
509 return &buffer[3];
512 return &buffer[0];
518 /* send the packet in buffer. */
520 static void
521 putpacket (unsigned char *buffer)
523 unsigned char checksum;
524 int count;
525 unsigned char ch;
527 /* $<packet info>#<checksum>. */
530 putDebugChar('$');
531 checksum = 0;
532 count = 0;
534 while (ch = buffer[count])
536 putDebugChar(ch);
537 checksum += ch;
538 count += 1;
541 putDebugChar('#');
542 putDebugChar(hexchars[checksum >> 4]);
543 putDebugChar(hexchars[checksum & 0xf]);
546 while (getDebugChar() != '+');
549 /* Indicate to caller of mem2hex or hex2mem that there has been an
550 error. */
551 static volatile int mem_err = 0;
553 /* Convert the memory pointed to by mem into hex, placing result in buf.
554 * Return a pointer to the last char put in buf (null), in case of mem fault,
555 * return 0.
556 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
557 * a 0, else treat a fault like any other fault in the stub.
560 static unsigned char *
561 mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault)
563 unsigned char ch;
565 set_mem_fault_trap(may_fault);
567 while (count-- > 0)
569 ch = *mem++;
570 if (mem_err)
571 return 0;
572 *buf++ = hexchars[ch >> 4];
573 *buf++ = hexchars[ch & 0xf];
576 *buf = 0;
578 set_mem_fault_trap(0);
580 return buf;
583 /* convert the hex array pointed to by buf into binary to be placed in mem
584 * return a pointer to the character AFTER the last byte written */
586 static char *
587 hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
589 int i;
590 unsigned char ch;
592 set_mem_fault_trap(may_fault);
594 for (i=0; i<count; i++)
596 ch = hex(*buf++) << 4;
597 ch |= hex(*buf++);
598 *mem++ = ch;
599 if (mem_err)
600 return 0;
603 set_mem_fault_trap(0);
605 return mem;
608 /* This table contains the mapping between SPARC hardware trap types, and
609 signals, which are primarily what GDB understands. It also indicates
610 which hardware traps we need to commandeer when initializing the stub. */
612 static struct hard_trap_info
614 unsigned char tt; /* Trap type code for SPARClite */
615 unsigned char signo; /* Signal that we map this trap into */
616 } hard_trap_info[] = {
617 {1, SIGSEGV}, /* instruction access exception */
618 {0x3b, SIGSEGV}, /* instruction access error */
619 {2, SIGILL}, /* illegal instruction */
620 {3, SIGILL}, /* privileged instruction */
621 {4, SIGEMT}, /* fp disabled */
622 {0x24, SIGEMT}, /* cp disabled */
623 {7, SIGBUS}, /* mem address not aligned */
624 {0x29, SIGSEGV}, /* data access exception */
625 {10, SIGEMT}, /* tag overflow */
626 {128+1, SIGTRAP}, /* ta 1 - normal breakpoint instruction */
627 {0, 0} /* Must be last */
630 /* Set up exception handlers for tracing and breakpoints */
632 void
633 set_debug_traps (void)
635 struct hard_trap_info *ht;
637 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
638 exceptionHandler(ht->tt, trap_low);
640 initialized = 1;
643 asm ("
644 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
645 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
646 ! 0 would ever contain code that could mem fault. This routine will skip
647 ! past the faulting instruction after setting mem_err.
649 .text
650 .align 4
652 _fltr_set_mem_err:
653 sethi %hi(_mem_err), %l0
654 st %l1, [%l0 + %lo(_mem_err)]
655 jmpl %l2, %g0
656 rett %l2+4
659 static void
660 set_mem_fault_trap (int enable)
662 extern void fltr_set_mem_err();
663 mem_err = 0;
665 if (enable)
666 exceptionHandler(0x29, fltr_set_mem_err);
667 else
668 exceptionHandler(0x29, trap_low);
671 asm ("
672 .text
673 .align 4
675 _dummy_hw_breakpoint:
676 jmpl %l2, %g0
677 rett %l2+4
682 static void
683 set_hw_breakpoint_trap (int enable)
685 extern void dummy_hw_breakpoint();
687 if (enable)
688 exceptionHandler(255, dummy_hw_breakpoint);
689 else
690 exceptionHandler(255, trap_low);
693 static void
694 get_in_break_mode (void)
696 #if 0
697 int x;
698 mesg("get_in_break_mode, sp = ");
699 phex(&x);
700 #endif
701 set_hw_breakpoint_trap(1);
703 asm("
704 sethi %hi(0xff10), %l4
705 or %l4, %lo(0xff10), %l4
706 sta %g0, [%l4]0x1
712 set_hw_breakpoint_trap(0);
715 /* Convert the SPARC hardware trap type code to a unix signal number. */
717 static int
718 computeSignal (int tt)
720 struct hard_trap_info *ht;
722 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
723 if (ht->tt == tt)
724 return ht->signo;
726 return SIGHUP; /* default for things we don't know about */
730 * While we find nice hex chars, build an int.
731 * Return number of chars processed.
734 static int
735 hexToInt(char **ptr, int *intValue)
737 int numChars = 0;
738 int hexValue;
740 *intValue = 0;
742 while (**ptr)
744 hexValue = hex(**ptr);
745 if (hexValue < 0)
746 break;
748 *intValue = (*intValue << 4) | hexValue;
749 numChars ++;
751 (*ptr)++;
754 return (numChars);
758 * This function does all command procesing for interfacing to gdb. It
759 * returns 1 if you should skip the instruction at the trap address, 0
760 * otherwise.
763 static void
764 handle_exception (unsigned long *registers)
766 int tt; /* Trap type */
767 int sigval;
768 int addr;
769 int length;
770 char *ptr;
771 unsigned long *sp;
772 unsigned long dsr;
774 /* First, we must force all of the windows to be spilled out */
776 asm("
777 ! Ugh. sparclet has broken save
778 !save %sp, -64, %sp
779 save
780 add %fp,-64,%sp
781 !save %sp, -64, %sp
782 save
783 add %fp,-64,%sp
784 !save %sp, -64, %sp
785 save
786 add %fp,-64,%sp
787 !save %sp, -64, %sp
788 save
789 add %fp,-64,%sp
790 !save %sp, -64, %sp
791 save
792 add %fp,-64,%sp
793 !save %sp, -64, %sp
794 save
795 add %fp,-64,%sp
796 !save %sp, -64, %sp
797 save
798 add %fp,-64,%sp
799 !save %sp, -64, %sp
800 save
801 add %fp,-64,%sp
802 restore
803 restore
804 restore
805 restore
806 restore
807 restore
808 restore
809 restore
812 if (registers[PC] == (unsigned long)breakinst)
814 registers[PC] = registers[NPC];
815 registers[NPC] += 4;
817 sp = (unsigned long *)registers[SP];
819 tt = (registers[TBR] >> 4) & 0xff;
821 /* reply to host that an exception has occurred */
822 sigval = computeSignal(tt);
823 ptr = remcomOutBuffer;
825 *ptr++ = 'T';
826 *ptr++ = hexchars[sigval >> 4];
827 *ptr++ = hexchars[sigval & 0xf];
829 *ptr++ = hexchars[PC >> 4];
830 *ptr++ = hexchars[PC & 0xf];
831 *ptr++ = ':';
832 ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
833 *ptr++ = ';';
835 *ptr++ = hexchars[FP >> 4];
836 *ptr++ = hexchars[FP & 0xf];
837 *ptr++ = ':';
838 ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
839 *ptr++ = ';';
841 *ptr++ = hexchars[SP >> 4];
842 *ptr++ = hexchars[SP & 0xf];
843 *ptr++ = ':';
844 ptr = mem2hex((char *)&sp, ptr, 4, 0);
845 *ptr++ = ';';
847 *ptr++ = hexchars[NPC >> 4];
848 *ptr++ = hexchars[NPC & 0xf];
849 *ptr++ = ':';
850 ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
851 *ptr++ = ';';
853 *ptr++ = hexchars[O7 >> 4];
854 *ptr++ = hexchars[O7 & 0xf];
855 *ptr++ = ':';
856 ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
857 *ptr++ = ';';
859 *ptr++ = 0;
861 putpacket(remcomOutBuffer);
863 while (1)
865 remcomOutBuffer[0] = 0;
867 ptr = getpacket();
868 switch (*ptr++)
870 case '?':
871 remcomOutBuffer[0] = 'S';
872 remcomOutBuffer[1] = hexchars[sigval >> 4];
873 remcomOutBuffer[2] = hexchars[sigval & 0xf];
874 remcomOutBuffer[3] = 0;
875 break;
877 case 'd':
878 remote_debug = !(remote_debug); /* toggle debug flag */
879 break;
881 case 'g': /* return the value of the CPU registers */
883 ptr = remcomOutBuffer;
884 ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
885 ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
886 memset(ptr, '0', 32 * 8); /* Floating point */
887 ptr = mem2hex((char *)&registers[Y],
888 ptr + 32 * 4 * 2,
889 8 * 4,
890 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
891 ptr = mem2hex((char *)&registers[CCSR],
892 ptr,
893 8 * 4,
894 0); /* CCSR, CCPR, CCCRCR, CCOR, CCOBR, CCIBR, CCIR */
895 ptr = mem2hex((char *)&registers[ASR1],
896 ptr,
897 8 * 4,
898 0); /* ASR1,ASR15,ASR17,ASR18,ASR19,ASR20,ASR21,ASR22 */
899 #if 0 /* not implemented */
900 ptr = mem2hex((char *) &registers[AWR0],
901 ptr,
902 32 * 4,
903 0); /* Alternate Window Registers */
904 #endif
906 break;
908 case 'G': /* set value of all the CPU registers - return OK */
909 case 'P': /* set value of one CPU register - return OK */
911 unsigned long *newsp, psr;
913 psr = registers[PSR];
915 if (ptr[-1] == 'P') /* do a single register */
917 int regno;
919 if (hexToInt (&ptr, &regno)
920 && *ptr++ == '=')
921 if (regno >= L0 && regno <= I7)
922 hex2mem (ptr, sp + regno - L0, 4, 0);
923 else
924 hex2mem (ptr, (char *)&registers[regno], 4, 0);
925 else
927 strcpy (remcomOutBuffer, "E01");
928 break;
931 else
933 hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
934 hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
935 hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y],
936 8 * 4, 0); /* Y,PSR,WIM,TBR,PC,NPC,FPSR,CPSR */
937 hex2mem(ptr + 72 * 4 * 2, (char *)&registers[CCSR],
938 8 * 4, 0); /* CCSR,CCPR,CCCRCR,CCOR,CCOBR,CCIBR,CCIR */
939 hex2mem(ptr + 80 * 4 * 2, (char *)&registers[ASR1],
940 8 * 4, 0); /* ASR1 ... ASR22 */
941 #if 0 /* not implemented */
942 hex2mem(ptr + 88 * 4 * 2, (char *)&registers[AWR0],
943 8 * 4, 0); /* Alternate Window Registers */
944 #endif
946 /* See if the stack pointer has moved. If so, then copy the saved
947 locals and ins to the new location. This keeps the window
948 overflow and underflow routines happy. */
950 newsp = (unsigned long *)registers[SP];
951 if (sp != newsp)
952 sp = memcpy(newsp, sp, 16 * 4);
954 /* Don't allow CWP to be modified. */
956 if (psr != registers[PSR])
957 registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
959 strcpy(remcomOutBuffer,"OK");
961 break;
963 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
964 /* Try to read %x,%x. */
966 if (hexToInt(&ptr, &addr)
967 && *ptr++ == ','
968 && hexToInt(&ptr, &length))
970 if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
971 break;
973 strcpy (remcomOutBuffer, "E03");
975 else
976 strcpy(remcomOutBuffer,"E01");
977 break;
979 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
980 /* Try to read '%x,%x:'. */
982 if (hexToInt(&ptr, &addr)
983 && *ptr++ == ','
984 && hexToInt(&ptr, &length)
985 && *ptr++ == ':')
987 if (hex2mem(ptr, (char *)addr, length, 1))
988 strcpy(remcomOutBuffer, "OK");
989 else
990 strcpy(remcomOutBuffer, "E03");
992 else
993 strcpy(remcomOutBuffer, "E02");
994 break;
996 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
997 /* try to read optional parameter, pc unchanged if no parm */
999 if (hexToInt(&ptr, &addr))
1001 registers[PC] = addr;
1002 registers[NPC] = addr + 4;
1005 /* Need to flush the instruction cache here, as we may have deposited a
1006 breakpoint, and the icache probably has no way of knowing that a data ref to
1007 some location may have changed something that is in the instruction cache.
1010 flush_i_cache();
1011 return;
1013 /* kill the program */
1014 case 'k' : /* do nothing */
1015 break;
1016 #if 0
1017 case 't': /* Test feature */
1018 asm (" std %f30,[%sp]");
1019 break;
1020 #endif
1021 case 'r': /* Reset */
1022 asm ("call 0
1023 nop ");
1024 break;
1025 } /* switch */
1027 /* reply to the request */
1028 putpacket(remcomOutBuffer);
1032 /* This function will generate a breakpoint exception. It is used at the
1033 beginning of a program to sync up with a debugger and can be used
1034 otherwise as a quick means to stop program execution and "break" into
1035 the debugger. */
1037 void
1038 breakpoint (void)
1040 if (!initialized)
1041 return;
1043 asm(" .globl _breakinst
1045 _breakinst: ta 1
1049 static void
1050 hw_breakpoint (void)
1052 asm("
1053 ta 127
1057 #if 0 /* experimental and never finished, left here for reference */
1058 static void
1059 splet_temp(void)
1061 asm(" sub %sp,(16+1+6+1+121)*4,%sp ! Make room for input & locals
1062 ! + hidden arg + arg spill
1063 ! + doubleword alignment
1064 ! + registers[121]
1066 ! Leave a trail of breadcrumbs! (save register save area for debugging)
1067 mov %sp, %l0
1068 add %l0, 24*4, %l0
1069 sethi %hi(_debug_registers), %l1
1070 st %l0, [%lo(_debug_registers) + %l1]
1072 ! Save the Alternate Register Set: (not implemented yet)
1073 ! To save the Alternate Register set, we must:
1074 ! 1) Save the current SP in some global location.
1075 ! 2) Swap the register sets.
1076 ! 3) Save the Alternate SP in the Y register
1077 ! 4) Fetch the SP that we saved in step 1.
1078 ! 5) Use that to save the rest of the regs (not forgetting ASP in Y)
1079 ! 6) Restore the Alternate SP from Y
1080 ! 7) Swap the registers back.
1082 ! 1) Copy the current stack pointer to global _SAVED_STACK_POINTER:
1083 sethi %hi(_saved_stack_pointer), %l0
1084 st %sp, [%lo(_saved_stack_pointer) + %l0]
1086 ! 2) Swap the register sets:
1087 mov %psr, %l1
1088 sethi %hi(0x10000), %l2
1089 xor %l1, %l2, %l1
1090 mov %l1, %psr
1091 nop ! 3 nops after write to %psr (needed?)
1095 ! 3) Save Alternate L0 in Y
1096 wr %l0, 0, %y
1098 ! 4) Load former SP into alternate SP, using L0
1099 sethi %hi(_saved_stack_pointer), %l0
1100 or %lo(_saved_stack_pointer), %l0, %l0
1101 swap [%l0], %sp
1103 ! 4.5) Restore alternate L0
1104 rd %y, %l0
1106 ! 5) Save the Alternate Window Registers
1107 st %r0, [%sp + (24 + 88) * 4] ! AWR0
1108 st %r1, [%sp + (24 + 89) * 4] ! AWR1
1109 st %r2, [%sp + (24 + 90) * 4] ! AWR2
1110 st %r3, [%sp + (24 + 91) * 4] ! AWR3
1111 st %r4, [%sp + (24 + 92) * 4] ! AWR4
1112 st %r5, [%sp + (24 + 93) * 4] ! AWR5
1113 st %r6, [%sp + (24 + 94) * 4] ! AWR6
1114 st %r7, [%sp + (24 + 95) * 4] ! AWR7
1115 st %r8, [%sp + (24 + 96) * 4] ! AWR8
1116 st %r9, [%sp + (24 + 97) * 4] ! AWR9
1117 st %r10, [%sp + (24 + 98) * 4] ! AWR10
1118 st %r11, [%sp + (24 + 99) * 4] ! AWR11
1119 st %r12, [%sp + (24 + 100) * 4] ! AWR12
1120 st %r13, [%sp + (24 + 101) * 4] ! AWR13
1121 ! st %r14, [%sp + (24 + 102) * 4] ! AWR14 (SP)
1122 st %r15, [%sp + (24 + 103) * 4] ! AWR15
1123 st %r16, [%sp + (24 + 104) * 4] ! AWR16
1124 st %r17, [%sp + (24 + 105) * 4] ! AWR17
1125 st %r18, [%sp + (24 + 106) * 4] ! AWR18
1126 st %r19, [%sp + (24 + 107) * 4] ! AWR19
1127 st %r20, [%sp + (24 + 108) * 4] ! AWR20
1128 st %r21, [%sp + (24 + 109) * 4] ! AWR21
1129 st %r22, [%sp + (24 + 110) * 4] ! AWR22
1130 st %r23, [%sp + (24 + 111) * 4] ! AWR23
1131 st %r24, [%sp + (24 + 112) * 4] ! AWR24
1132 st %r25, [%sp + (24 + 113) * 4] ! AWR25
1133 st %r26, [%sp + (24 + 114) * 4] ! AWR26
1134 st %r27, [%sp + (24 + 115) * 4] ! AWR27
1135 st %r28, [%sp + (24 + 116) * 4] ! AWR28
1136 st %r29, [%sp + (24 + 117) * 4] ! AWR29
1137 st %r30, [%sp + (24 + 118) * 4] ! AWR30
1138 st %r31, [%sp + (24 + 119) * 4] ! AWR21
1140 ! Get the Alternate PSR (I hope...)
1142 rd %psr, %l2
1143 st %l2, [%sp + (24 + 120) * 4] ! APSR
1145 ! Don't forget the alternate stack pointer
1147 rd %y, %l3
1148 st %l3, [%sp + (24 + 102) * 4] ! AWR14 (SP)
1150 ! 6) Restore the Alternate SP (saved in Y)
1152 rd %y, %o6
1155 ! 7) Swap the registers back:
1157 mov %psr, %l1
1158 sethi %hi(0x10000), %l2
1159 xor %l1, %l2, %l1
1160 mov %l1, %psr
1161 nop ! 3 nops after write to %psr (needed?)
1167 #endif