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