]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/sparclet-stub.c
Initial creation of sourceware repository
[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 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 /* In case GDB is started before us, ack any packets (presumably
653 "$?#xx") sitting there. */
654 putDebugChar ('+');
655
656 initialized = 1;
657 }
658
659 asm ("
660 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
661 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
662 ! 0 would ever contain code that could mem fault. This routine will skip
663 ! past the faulting instruction after setting mem_err.
664
665 .text
666 .align 4
667
668 _fltr_set_mem_err:
669 sethi %hi(_mem_err), %l0
670 st %l1, [%l0 + %lo(_mem_err)]
671 jmpl %l2, %g0
672 rett %l2+4
673 ");
674
675 static void
676 set_mem_fault_trap(enable)
677 int enable;
678 {
679 extern void fltr_set_mem_err();
680 mem_err = 0;
681
682 if (enable)
683 exceptionHandler(0x29, fltr_set_mem_err);
684 else
685 exceptionHandler(0x29, trap_low);
686 }
687
688 asm ("
689 .text
690 .align 4
691
692 _dummy_hw_breakpoint:
693 jmpl %l2, %g0
694 rett %l2+4
695 nop
696 nop
697 ");
698
699 static void
700 set_hw_breakpoint_trap(enable)
701 int enable;
702 {
703 extern void dummy_hw_breakpoint();
704
705 if (enable)
706 exceptionHandler(255, dummy_hw_breakpoint);
707 else
708 exceptionHandler(255, trap_low);
709 }
710
711 static void
712 get_in_break_mode()
713 {
714 #if 0
715 int x;
716 mesg("get_in_break_mode, sp = ");
717 phex(&x);
718 #endif
719 set_hw_breakpoint_trap(1);
720
721 asm("
722 sethi %hi(0xff10), %l4
723 or %l4, %lo(0xff10), %l4
724 sta %g0, [%l4]0x1
725 nop
726 nop
727 nop
728 ");
729
730 set_hw_breakpoint_trap(0);
731 }
732
733 /* Convert the SPARC hardware trap type code to a unix signal number. */
734
735 static int
736 computeSignal(tt)
737 int tt;
738 {
739 struct hard_trap_info *ht;
740
741 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
742 if (ht->tt == tt)
743 return ht->signo;
744
745 return SIGHUP; /* default for things we don't know about */
746 }
747
748 /*
749 * While we find nice hex chars, build an int.
750 * Return number of chars processed.
751 */
752
753 static int
754 hexToInt(char **ptr, int *intValue)
755 {
756 int numChars = 0;
757 int hexValue;
758
759 *intValue = 0;
760
761 while (**ptr)
762 {
763 hexValue = hex(**ptr);
764 if (hexValue < 0)
765 break;
766
767 *intValue = (*intValue << 4) | hexValue;
768 numChars ++;
769
770 (*ptr)++;
771 }
772
773 return (numChars);
774 }
775
776 /*
777 * This function does all command procesing for interfacing to gdb. It
778 * returns 1 if you should skip the instruction at the trap address, 0
779 * otherwise.
780 */
781
782 static void
783 handle_exception (registers)
784 unsigned long *registers;
785 {
786 int tt; /* Trap type */
787 int sigval;
788 int addr;
789 int length;
790 char *ptr;
791 unsigned long *sp;
792 unsigned long dsr;
793
794 /* First, we must force all of the windows to be spilled out */
795
796 asm("
797 ! Ugh. sparclet has broken save
798 !save %sp, -64, %sp
799 save
800 add %fp,-64,%sp
801 !save %sp, -64, %sp
802 save
803 add %fp,-64,%sp
804 !save %sp, -64, %sp
805 save
806 add %fp,-64,%sp
807 !save %sp, -64, %sp
808 save
809 add %fp,-64,%sp
810 !save %sp, -64, %sp
811 save
812 add %fp,-64,%sp
813 !save %sp, -64, %sp
814 save
815 add %fp,-64,%sp
816 !save %sp, -64, %sp
817 save
818 add %fp,-64,%sp
819 !save %sp, -64, %sp
820 save
821 add %fp,-64,%sp
822 restore
823 restore
824 restore
825 restore
826 restore
827 restore
828 restore
829 restore
830 ");
831
832 if (registers[PC] == (unsigned long)breakinst)
833 {
834 registers[PC] = registers[NPC];
835 registers[NPC] += 4;
836 }
837 sp = (unsigned long *)registers[SP];
838
839 tt = (registers[TBR] >> 4) & 0xff;
840
841 /* reply to host that an exception has occurred */
842 sigval = computeSignal(tt);
843 ptr = remcomOutBuffer;
844
845 *ptr++ = 'T';
846 *ptr++ = hexchars[sigval >> 4];
847 *ptr++ = hexchars[sigval & 0xf];
848
849 *ptr++ = hexchars[PC >> 4];
850 *ptr++ = hexchars[PC & 0xf];
851 *ptr++ = ':';
852 ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
853 *ptr++ = ';';
854
855 *ptr++ = hexchars[FP >> 4];
856 *ptr++ = hexchars[FP & 0xf];
857 *ptr++ = ':';
858 ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
859 *ptr++ = ';';
860
861 *ptr++ = hexchars[SP >> 4];
862 *ptr++ = hexchars[SP & 0xf];
863 *ptr++ = ':';
864 ptr = mem2hex((char *)&sp, ptr, 4, 0);
865 *ptr++ = ';';
866
867 *ptr++ = hexchars[NPC >> 4];
868 *ptr++ = hexchars[NPC & 0xf];
869 *ptr++ = ':';
870 ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
871 *ptr++ = ';';
872
873 *ptr++ = hexchars[O7 >> 4];
874 *ptr++ = hexchars[O7 & 0xf];
875 *ptr++ = ':';
876 ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
877 *ptr++ = ';';
878
879 *ptr++ = 0;
880
881 putpacket(remcomOutBuffer);
882
883 while (1)
884 {
885 remcomOutBuffer[0] = 0;
886
887 getpacket(remcomInBuffer);
888 switch (remcomInBuffer[0])
889 {
890 case '?':
891 remcomOutBuffer[0] = 'S';
892 remcomOutBuffer[1] = hexchars[sigval >> 4];
893 remcomOutBuffer[2] = hexchars[sigval & 0xf];
894 remcomOutBuffer[3] = 0;
895 break;
896
897 case 'd':
898 remote_debug = !(remote_debug); /* toggle debug flag */
899 break;
900
901 case 'g': /* return the value of the CPU registers */
902 {
903 ptr = remcomOutBuffer;
904 ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
905 ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
906 memset(ptr, '0', 32 * 8); /* Floating point */
907 ptr = mem2hex((char *)&registers[Y],
908 ptr + 32 * 4 * 2,
909 8 * 4,
910 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
911 ptr = mem2hex((char *)&registers[CCSR],
912 ptr,
913 8 * 4,
914 0); /* CCSR, CCPR, CCCRCR, CCOR, CCOBR, CCIBR, CCIR */
915 ptr = mem2hex((char *)&registers[ASR1],
916 ptr,
917 8 * 4,
918 0); /* ASR1,ASR15,ASR17,ASR18,ASR19,ASR20,ASR21,ASR22 */
919 #if 0 /* not implemented */
920 ptr = mem2hex((char *) &registers[AWR0],
921 ptr,
922 32 * 4,
923 0); /* Alternate Window Registers */
924 #endif
925 }
926 break;
927
928 case 'G': /* set value of all the CPU registers - return OK */
929 case 'P': /* set value of one CPU register - return OK */
930 {
931 unsigned long *newsp, psr;
932
933 psr = registers[PSR];
934
935 ptr = &remcomInBuffer[1];
936
937 if (remcomInBuffer[0] == 'P') /* do a single register */
938 {
939 int regno;
940
941 if (hexToInt (&ptr, &regno)
942 && *ptr++ == '=')
943 if (regno >= L0 && regno <= I7)
944 hex2mem (ptr, sp + regno - L0, 4, 0);
945 else
946 hex2mem (ptr, (char *)&registers[regno], 4, 0);
947 else
948 {
949 strcpy (remcomOutBuffer, "P01");
950 break;
951 }
952 }
953 else
954 {
955 hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
956 hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
957 hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y],
958 8 * 4, 0); /* Y,PSR,WIM,TBR,PC,NPC,FPSR,CPSR */
959 hex2mem(ptr + 72 * 4 * 2, (char *)&registers[CCSR],
960 8 * 4, 0); /* CCSR,CCPR,CCCRCR,CCOR,CCOBR,CCIBR,CCIR */
961 hex2mem(ptr + 80 * 4 * 2, (char *)&registers[ASR1],
962 8 * 4, 0); /* ASR1 ... ASR22 */
963 #if 0 /* not implemented */
964 hex2mem(ptr + 88 * 4 * 2, (char *)&registers[AWR0],
965 8 * 4, 0); /* Alternate Window Registers */
966 #endif
967 }
968 /* See if the stack pointer has moved. If so, then copy the saved
969 locals and ins to the new location. This keeps the window
970 overflow and underflow routines happy. */
971
972 newsp = (unsigned long *)registers[SP];
973 if (sp != newsp)
974 sp = memcpy(newsp, sp, 16 * 4);
975
976 /* Don't allow CWP to be modified. */
977
978 if (psr != registers[PSR])
979 registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
980
981 strcpy(remcomOutBuffer,"OK");
982 }
983 break;
984
985 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
986 /* Try to read %x,%x. */
987
988 ptr = &remcomInBuffer[1];
989
990 if (hexToInt(&ptr, &addr)
991 && *ptr++ == ','
992 && hexToInt(&ptr, &length))
993 {
994 if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
995 break;
996
997 strcpy (remcomOutBuffer, "E03");
998 }
999 else
1000 strcpy(remcomOutBuffer,"E01");
1001 break;
1002
1003 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1004 /* Try to read '%x,%x:'. */
1005
1006 ptr = &remcomInBuffer[1];
1007
1008 if (hexToInt(&ptr, &addr)
1009 && *ptr++ == ','
1010 && hexToInt(&ptr, &length)
1011 && *ptr++ == ':')
1012 {
1013 if (hex2mem(ptr, (char *)addr, length, 1))
1014 strcpy(remcomOutBuffer, "OK");
1015 else
1016 strcpy(remcomOutBuffer, "E03");
1017 }
1018 else
1019 strcpy(remcomOutBuffer, "E02");
1020 break;
1021
1022 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
1023 /* try to read optional parameter, pc unchanged if no parm */
1024
1025 ptr = &remcomInBuffer[1];
1026 if (hexToInt(&ptr, &addr))
1027 {
1028 registers[PC] = addr;
1029 registers[NPC] = addr + 4;
1030 }
1031
1032 /* Need to flush the instruction cache here, as we may have deposited a
1033 breakpoint, and the icache probably has no way of knowing that a data ref to
1034 some location may have changed something that is in the instruction cache.
1035 */
1036
1037 flush_i_cache();
1038 return;
1039
1040 /* kill the program */
1041 case 'k' : /* do nothing */
1042 break;
1043 #if 0
1044 case 't': /* Test feature */
1045 asm (" std %f30,[%sp]");
1046 break;
1047 #endif
1048 case 'r': /* Reset */
1049 asm ("call 0
1050 nop ");
1051 break;
1052
1053 #if 0
1054 Disabled until we can unscrew this properly
1055
1056 case 'b': /* bBB... Set baud rate to BB... */
1057 {
1058 int baudrate;
1059 extern void set_timer_3();
1060
1061 ptr = &remcomInBuffer[1];
1062 if (!hexToInt(&ptr, &baudrate))
1063 {
1064 strcpy(remcomOutBuffer,"B01");
1065 break;
1066 }
1067
1068 /* Convert baud rate to uart clock divider */
1069 switch (baudrate)
1070 {
1071 case 38400:
1072 baudrate = 16;
1073 break;
1074 case 19200:
1075 baudrate = 33;
1076 break;
1077 case 9600:
1078 baudrate = 65;
1079 break;
1080 default:
1081 strcpy(remcomOutBuffer,"B02");
1082 goto x1;
1083 }
1084
1085 putpacket("OK"); /* Ack before changing speed */
1086 set_timer_3(baudrate); /* Set it */
1087 }
1088 x1: break;
1089 #endif
1090 } /* switch */
1091
1092 /* reply to the request */
1093 putpacket(remcomOutBuffer);
1094 }
1095 }
1096
1097 /* This function will generate a breakpoint exception. It is used at the
1098 beginning of a program to sync up with a debugger and can be used
1099 otherwise as a quick means to stop program execution and "break" into
1100 the debugger. */
1101
1102 void
1103 breakpoint()
1104 {
1105 if (!initialized)
1106 return;
1107
1108 asm(" .globl _breakinst
1109
1110 _breakinst: ta 1
1111 ");
1112 }
1113
1114 static void
1115 hw_breakpoint()
1116 {
1117 asm("
1118 ta 127
1119 ");
1120 }
1121
1122 #if 0 /* experimental and never finished, left here for reference */
1123 static void
1124 splet_temp(void)
1125 {
1126 asm(" sub %sp,(16+1+6+1+121)*4,%sp ! Make room for input & locals
1127 ! + hidden arg + arg spill
1128 ! + doubleword alignment
1129 ! + registers[121]
1130
1131 ! Leave a trail of breadcrumbs! (save register save area for debugging)
1132 mov %sp, %l0
1133 add %l0, 24*4, %l0
1134 sethi %hi(_debug_registers), %l1
1135 st %l0, [%lo(_debug_registers) + %l1]
1136
1137 ! Save the Alternate Register Set: (not implemented yet)
1138 ! To save the Alternate Register set, we must:
1139 ! 1) Save the current SP in some global location.
1140 ! 2) Swap the register sets.
1141 ! 3) Save the Alternate SP in the Y register
1142 ! 4) Fetch the SP that we saved in step 1.
1143 ! 5) Use that to save the rest of the regs (not forgetting ASP in Y)
1144 ! 6) Restore the Alternate SP from Y
1145 ! 7) Swap the registers back.
1146
1147 ! 1) Copy the current stack pointer to global _SAVED_STACK_POINTER:
1148 sethi %hi(_saved_stack_pointer), %l0
1149 st %sp, [%lo(_saved_stack_pointer) + %l0]
1150
1151 ! 2) Swap the register sets:
1152 mov %psr, %l1
1153 sethi %hi(0x10000), %l2
1154 xor %l1, %l2, %l1
1155 mov %l1, %psr
1156 nop ! 3 nops after write to %psr (needed?)
1157 nop
1158 nop
1159
1160 ! 3) Save Alternate L0 in Y
1161 wr %l0, 0, %y
1162
1163 ! 4) Load former SP into alternate SP, using L0
1164 sethi %hi(_saved_stack_pointer), %l0
1165 or %lo(_saved_stack_pointer), %l0, %l0
1166 swap [%l0], %sp
1167
1168 ! 4.5) Restore alternate L0
1169 rd %y, %l0
1170
1171 ! 5) Save the Alternate Window Registers
1172 st %r0, [%sp + (24 + 88) * 4] ! AWR0
1173 st %r1, [%sp + (24 + 89) * 4] ! AWR1
1174 st %r2, [%sp + (24 + 90) * 4] ! AWR2
1175 st %r3, [%sp + (24 + 91) * 4] ! AWR3
1176 st %r4, [%sp + (24 + 92) * 4] ! AWR4
1177 st %r5, [%sp + (24 + 93) * 4] ! AWR5
1178 st %r6, [%sp + (24 + 94) * 4] ! AWR6
1179 st %r7, [%sp + (24 + 95) * 4] ! AWR7
1180 st %r8, [%sp + (24 + 96) * 4] ! AWR8
1181 st %r9, [%sp + (24 + 97) * 4] ! AWR9
1182 st %r10, [%sp + (24 + 98) * 4] ! AWR10
1183 st %r11, [%sp + (24 + 99) * 4] ! AWR11
1184 st %r12, [%sp + (24 + 100) * 4] ! AWR12
1185 st %r13, [%sp + (24 + 101) * 4] ! AWR13
1186 ! st %r14, [%sp + (24 + 102) * 4] ! AWR14 (SP)
1187 st %r15, [%sp + (24 + 103) * 4] ! AWR15
1188 st %r16, [%sp + (24 + 104) * 4] ! AWR16
1189 st %r17, [%sp + (24 + 105) * 4] ! AWR17
1190 st %r18, [%sp + (24 + 106) * 4] ! AWR18
1191 st %r19, [%sp + (24 + 107) * 4] ! AWR19
1192 st %r20, [%sp + (24 + 108) * 4] ! AWR20
1193 st %r21, [%sp + (24 + 109) * 4] ! AWR21
1194 st %r22, [%sp + (24 + 110) * 4] ! AWR22
1195 st %r23, [%sp + (24 + 111) * 4] ! AWR23
1196 st %r24, [%sp + (24 + 112) * 4] ! AWR24
1197 st %r25, [%sp + (24 + 113) * 4] ! AWR25
1198 st %r26, [%sp + (24 + 114) * 4] ! AWR26
1199 st %r27, [%sp + (24 + 115) * 4] ! AWR27
1200 st %r28, [%sp + (24 + 116) * 4] ! AWR28
1201 st %r29, [%sp + (24 + 117) * 4] ! AWR29
1202 st %r30, [%sp + (24 + 118) * 4] ! AWR30
1203 st %r31, [%sp + (24 + 119) * 4] ! AWR21
1204
1205 ! Get the Alternate PSR (I hope...)
1206
1207 rd %psr, %l2
1208 st %l2, [%sp + (24 + 120) * 4] ! APSR
1209
1210 ! Don't forget the alternate stack pointer
1211
1212 rd %y, %l3
1213 st %l3, [%sp + (24 + 102) * 4] ! AWR14 (SP)
1214
1215 ! 6) Restore the Alternate SP (saved in Y)
1216
1217 rd %y, %o6
1218
1219
1220 ! 7) Swap the registers back:
1221
1222 mov %psr, %l1
1223 sethi %hi(0x10000), %l2
1224 xor %l1, %l2, %l1
1225 mov %l1, %psr
1226 nop ! 3 nops after write to %psr (needed?)
1227 nop
1228 nop
1229 ");
1230 }
1231
1232 #endif