Protoization.
[deliverable/binutils-gdb.git] / gdb / sparcl-stub.c
1 /****************************************************************************
2
3 THIS SOFTWARE IS NOT COPYRIGHTED
4
5 HP offers the following for use in the public domain. HP makes no
6 warranty with regard to the software or it's performance and the
7 user accepts the software "AS IS" with all faults.
8
9 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12
13 ****************************************************************************/
14
15 /****************************************************************************
16 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
17 *
18 * Module name: remcom.c $
19 * Revision: 1.34 $
20 * Date: 91/03/09 12:29:49 $
21 * Contributor: Lake Stevens Instrument Division$
22 *
23 * Description: low level support for gdb debugger. $
24 *
25 * Considerations: only works on target hardware $
26 *
27 * Written by: Glenn Engel $
28 * ModuleState: Experimental $
29 *
30 * NOTES: See Below $
31 *
32 * Modified for SPARC by Stu Grossman, Cygnus Support.
33 * Based on sparc-stub.c, it's modified for SPARClite Debug Unit hardware
34 * breakpoint support to create sparclite-stub.c, by Kung Hsu, Cygnus Support.
35 *
36 * This code has been extensively tested on the Fujitsu SPARClite demo board.
37 *
38 * To enable debugger support, two things need to happen. One, a
39 * call to set_debug_traps() is necessary in order to allow any breakpoints
40 * or error conditions to be properly intercepted and reported to gdb.
41 * Two, a breakpoint needs to be generated to begin communication. This
42 * is most easily accomplished by a call to breakpoint(). Breakpoint()
43 * simulates a breakpoint by executing a trap #1.
44 *
45 *************
46 *
47 * The following gdb commands are supported:
48 *
49 * command function Return value
50 *
51 * g return the value of the CPU registers hex data or ENN
52 * G set the value of the CPU registers OK or ENN
53 * P set the value of a single CPU register OK or ENN
54 *
55 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
56 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
57 *
58 * c Resume at current address SNN ( signal NN)
59 * cAA..AA Continue at address AA..AA SNN
60 *
61 * s Step one instruction SNN
62 * sAA..AA Step one instruction from AA..AA SNN
63 *
64 * k kill
65 *
66 * ? What was the last sigval ? SNN (signal NN)
67 *
68 * All commands and responses are sent with a packet which includes a
69 * checksum. A packet consists of
70 *
71 * $<packet info>#<checksum>.
72 *
73 * where
74 * <packet info> :: <characters representing the command or response>
75 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
76 *
77 * When a packet is received, it is first acknowledged with either '+' or '-'.
78 * '+' indicates a successful transfer. '-' indicates a failed transfer.
79 *
80 * Example:
81 *
82 * Host: Reply:
83 * $m0,10#2a +$00010203040506070809101112131415#42
84 *
85 ****************************************************************************/
86
87 #include <string.h>
88 #include <signal.h>
89 #include <sparclite.h>
90
91 /************************************************************************
92 *
93 * external low-level support routines
94 */
95
96 extern void putDebugChar (int c); /* write a single character */
97 extern int getDebugChar (void); /* read and return a single char */
98
99 /************************************************************************/
100 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
101 /* at least NUMREGBYTES*2 are needed for register packets */
102 #define BUFMAX 2048
103
104 static int initialized = 0; /* !0 means we've been initialized */
105
106 extern void breakinst ();
107 static void set_mem_fault_trap (int enable);
108 static void get_in_break_mode (void);
109
110 static const char hexchars[]="0123456789abcdef";
111
112 #define NUMREGS 80
113
114 /* Number of bytes of registers. */
115 #define NUMREGBYTES (NUMREGS * 4)
116 enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
117 O0, O1, O2, O3, O4, O5, SP, O7,
118 L0, L1, L2, L3, L4, L5, L6, L7,
119 I0, I1, I2, I3, I4, I5, FP, I7,
120
121 F0, F1, F2, F3, F4, F5, F6, F7,
122 F8, F9, F10, F11, F12, F13, F14, F15,
123 F16, F17, F18, F19, F20, F21, F22, F23,
124 F24, F25, F26, F27, F28, F29, F30, F31,
125 Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR,
126 DIA1, DIA2, DDA1, DDA2, DDV1, DDV2, DCR, DSR };
127
128 /*************************** ASSEMBLY CODE MACROS *************************/
129 /* */
130
131 extern void trap_low();
132
133 /* Create private copies of common functions used by the stub. This prevents
134 nasty interactions between app code and the stub (for instance if user steps
135 into strlen, etc..) */
136
137 static char *
138 strcpy (char *dst, const char *src)
139 {
140 char *retval = dst;
141
142 while ((*dst++ = *src++) != '\000');
143
144 return retval;
145 }
146
147 static void *
148 memcpy (void *vdst, const void *vsrc, int n)
149 {
150 char *dst = vdst;
151 const char *src = vsrc;
152 char *retval = dst;
153
154 while (n-- > 0)
155 *dst++ = *src++;
156
157 return retval;
158 }
159
160 asm("
161 .reserve trapstack, 1000 * 4, \"bss\", 8
162
163 .data
164 .align 4
165
166 in_trap_handler:
167 .word 0
168
169 .text
170 .align 4
171
172 ! This function is called when any SPARC trap (except window overflow or
173 ! underflow) occurs. It makes sure that the invalid register window is still
174 ! available before jumping into C code. It will also restore the world if you
175 ! return from handle_exception.
176 !
177 ! On entry, trap_low expects l1 and l2 to contain pc and npc respectivly.
178 ! Register usage throughout the routine is as follows:
179 !
180 ! l0 - psr
181 ! l1 - pc
182 ! l2 - npc
183 ! l3 - wim
184 ! l4 - scratch and y reg
185 ! l5 - scratch and tbr
186 ! l6 - unused
187 ! l7 - unused
188
189 .globl _trap_low
190 _trap_low:
191 mov %psr, %l0
192 mov %wim, %l3
193
194 srl %l3, %l0, %l4 ! wim >> cwp
195 cmp %l4, 1
196 bne window_fine ! Branch if not in the invalid window
197 nop
198
199 ! Handle window overflow
200
201 mov %g1, %l4 ! Save g1, we use it to hold the wim
202 srl %l3, 1, %g1 ! Rotate wim right
203 tst %g1
204 bg good_wim ! Branch if new wim is non-zero
205 nop
206
207 ! At this point, we need to bring a 1 into the high order bit of the wim.
208 ! Since we don't want to make any assumptions about the number of register
209 ! windows, we figure it out dynamically so as to setup the wim correctly.
210
211 not %g1 ! Fill g1 with ones
212 mov %g1, %wim ! Fill the wim with ones
213 nop
214 nop
215 nop
216 mov %wim, %g1 ! Read back the wim
217 inc %g1 ! Now g1 has 1 just to left of wim
218 srl %g1, 1, %g1 ! Now put 1 at top of wim
219 mov %g0, %wim ! Clear wim so that subsequent save
220 nop ! won't trap
221 nop
222 nop
223
224 good_wim:
225 save %g0, %g0, %g0 ! Slip into next window
226 mov %g1, %wim ! Install the new wim
227
228 std %l0, [%sp + 0 * 4] ! save L & I registers
229 std %l2, [%sp + 2 * 4]
230 std %l4, [%sp + 4 * 4]
231 std %l6, [%sp + 6 * 4]
232
233 std %i0, [%sp + 8 * 4]
234 std %i2, [%sp + 10 * 4]
235 std %i4, [%sp + 12 * 4]
236 std %i6, [%sp + 14 * 4]
237
238 restore ! Go back to trap window.
239 mov %l4, %g1 ! Restore %g1
240
241 window_fine:
242 sethi %hi(in_trap_handler), %l4
243 ld [%lo(in_trap_handler) + %l4], %l5
244 tst %l5
245 bg recursive_trap
246 inc %l5
247
248 set trapstack+1000*4, %sp ! Switch to trap stack
249
250 recursive_trap:
251 st %l5, [%lo(in_trap_handler) + %l4]
252 sub %sp,(16+1+6+1+80)*4,%sp ! Make room for input & locals
253 ! + hidden arg + arg spill
254 ! + doubleword alignment
255 ! + registers[72] local var
256
257 std %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
258 std %g2, [%sp + (24 + 2) * 4]
259 std %g4, [%sp + (24 + 4) * 4]
260 std %g6, [%sp + (24 + 6) * 4]
261
262 std %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
263 std %i2, [%sp + (24 + 10) * 4]
264 std %i4, [%sp + (24 + 12) * 4]
265 std %i6, [%sp + (24 + 14) * 4]
266
267 mov %y, %l4
268 mov %tbr, %l5
269 st %l4, [%sp + (24 + 64) * 4] ! Y
270 st %l0, [%sp + (24 + 65) * 4] ! PSR
271 st %l3, [%sp + (24 + 66) * 4] ! WIM
272 st %l5, [%sp + (24 + 67) * 4] ! TBR
273 st %l1, [%sp + (24 + 68) * 4] ! PC
274 st %l2, [%sp + (24 + 69) * 4] ! NPC
275
276 or %l0, 0xf20, %l4
277 mov %l4, %psr ! Turn on traps, disable interrupts
278
279 set 0x1000, %l1
280 btst %l1, %l0 ! FP enabled?
281 be no_fpstore
282 nop
283
284 ! Must save fsr first, to flush the FQ. This may cause a deferred fp trap, so
285 ! traps must be enabled to allow the trap handler to clean things up.
286
287 st %fsr, [%sp + (24 + 70) * 4]
288
289 std %f0, [%sp + (24 + 32) * 4]
290 std %f2, [%sp + (24 + 34) * 4]
291 std %f4, [%sp + (24 + 36) * 4]
292 std %f6, [%sp + (24 + 38) * 4]
293 std %f8, [%sp + (24 + 40) * 4]
294 std %f10, [%sp + (24 + 42) * 4]
295 std %f12, [%sp + (24 + 44) * 4]
296 std %f14, [%sp + (24 + 46) * 4]
297 std %f16, [%sp + (24 + 48) * 4]
298 std %f18, [%sp + (24 + 50) * 4]
299 std %f20, [%sp + (24 + 52) * 4]
300 std %f22, [%sp + (24 + 54) * 4]
301 std %f24, [%sp + (24 + 56) * 4]
302 std %f26, [%sp + (24 + 58) * 4]
303 std %f28, [%sp + (24 + 60) * 4]
304 std %f30, [%sp + (24 + 62) * 4]
305 no_fpstore:
306
307 call _handle_exception
308 add %sp, 24 * 4, %o0 ! Pass address of registers
309
310 ! Reload all of the registers that aren't on the stack
311
312 ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
313 ldd [%sp + (24 + 2) * 4], %g2
314 ldd [%sp + (24 + 4) * 4], %g4
315 ldd [%sp + (24 + 6) * 4], %g6
316
317 ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
318 ldd [%sp + (24 + 10) * 4], %i2
319 ldd [%sp + (24 + 12) * 4], %i4
320 ldd [%sp + (24 + 14) * 4], %i6
321
322
323 ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
324 ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
325
326 set 0x1000, %l5
327 btst %l5, %l1 ! FP enabled?
328 be no_fpreload
329 nop
330
331 ldd [%sp + (24 + 32) * 4], %f0
332 ldd [%sp + (24 + 34) * 4], %f2
333 ldd [%sp + (24 + 36) * 4], %f4
334 ldd [%sp + (24 + 38) * 4], %f6
335 ldd [%sp + (24 + 40) * 4], %f8
336 ldd [%sp + (24 + 42) * 4], %f10
337 ldd [%sp + (24 + 44) * 4], %f12
338 ldd [%sp + (24 + 46) * 4], %f14
339 ldd [%sp + (24 + 48) * 4], %f16
340 ldd [%sp + (24 + 50) * 4], %f18
341 ldd [%sp + (24 + 52) * 4], %f20
342 ldd [%sp + (24 + 54) * 4], %f22
343 ldd [%sp + (24 + 56) * 4], %f24
344 ldd [%sp + (24 + 58) * 4], %f26
345 ldd [%sp + (24 + 60) * 4], %f28
346 ldd [%sp + (24 + 62) * 4], %f30
347
348 ld [%sp + (24 + 70) * 4], %fsr
349 no_fpreload:
350
351 restore ! Ensure that previous window is valid
352 save %g0, %g0, %g0 ! by causing a window_underflow trap
353
354 mov %l0, %y
355 mov %l1, %psr ! Make sure that traps are disabled
356 ! for rett
357 sethi %hi(in_trap_handler), %l4
358 ld [%lo(in_trap_handler) + %l4], %l5
359 dec %l5
360 st %l5, [%lo(in_trap_handler) + %l4]
361
362 jmpl %l2, %g0 ! Restore old PC
363 rett %l3 ! Restore old nPC
364 ");
365
366 /* Convert ch from a hex digit to an int */
367
368 static int
369 hex (unsigned char ch)
370 {
371 if (ch >= 'a' && ch <= 'f')
372 return ch-'a'+10;
373 if (ch >= '0' && ch <= '9')
374 return ch-'0';
375 if (ch >= 'A' && ch <= 'F')
376 return ch-'A'+10;
377 return -1;
378 }
379
380 static char remcomInBuffer[BUFMAX];
381 static char remcomOutBuffer[BUFMAX];
382
383 /* scan for the sequence $<data>#<checksum> */
384
385 unsigned char *
386 getpacket (void)
387 {
388 unsigned char *buffer = &remcomInBuffer[0];
389 unsigned char checksum;
390 unsigned char xmitcsum;
391 int count;
392 char ch;
393
394 while (1)
395 {
396 /* wait around for the start character, ignore all other characters */
397 while ((ch = getDebugChar ()) != '$')
398 ;
399
400 retry:
401 checksum = 0;
402 xmitcsum = -1;
403 count = 0;
404
405 /* now, read until a # or end of buffer is found */
406 while (count < BUFMAX)
407 {
408 ch = getDebugChar ();
409 if (ch == '$')
410 goto retry;
411 if (ch == '#')
412 break;
413 checksum = checksum + ch;
414 buffer[count] = ch;
415 count = count + 1;
416 }
417 buffer[count] = 0;
418
419 if (ch == '#')
420 {
421 ch = getDebugChar ();
422 xmitcsum = hex (ch) << 4;
423 ch = getDebugChar ();
424 xmitcsum += hex (ch);
425
426 if (checksum != xmitcsum)
427 {
428 putDebugChar ('-'); /* failed checksum */
429 }
430 else
431 {
432 putDebugChar ('+'); /* successful transfer */
433
434 /* if a sequence char is present, reply the sequence ID */
435 if (buffer[2] == ':')
436 {
437 putDebugChar (buffer[0]);
438 putDebugChar (buffer[1]);
439
440 return &buffer[3];
441 }
442
443 return &buffer[0];
444 }
445 }
446 }
447 }
448
449 /* send the packet in buffer. */
450
451 static void
452 putpacket (unsigned char *buffer)
453 {
454 unsigned char checksum;
455 int count;
456 unsigned char ch;
457
458 /* $<packet info>#<checksum>. */
459 do
460 {
461 putDebugChar('$');
462 checksum = 0;
463 count = 0;
464
465 while (ch = buffer[count])
466 {
467 putDebugChar (ch);
468 checksum += ch;
469 count += 1;
470 }
471
472 putDebugChar('#');
473 putDebugChar(hexchars[checksum >> 4]);
474 putDebugChar(hexchars[checksum & 0xf]);
475
476 }
477 while (getDebugChar() != '+');
478 }
479
480 /* Indicate to caller of mem2hex or hex2mem that there has been an
481 error. */
482 static volatile int mem_err = 0;
483
484 /* Convert the memory pointed to by mem into hex, placing result in buf.
485 * Return a pointer to the last char put in buf (null), in case of mem fault,
486 * return 0.
487 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
488 * a 0, else treat a fault like any other fault in the stub.
489 */
490
491 static unsigned char *
492 mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault)
493 {
494 unsigned char ch;
495
496 set_mem_fault_trap(may_fault);
497
498 while (count-- > 0)
499 {
500 ch = *mem++;
501 if (mem_err)
502 return 0;
503 *buf++ = hexchars[ch >> 4];
504 *buf++ = hexchars[ch & 0xf];
505 }
506
507 *buf = 0;
508
509 set_mem_fault_trap(0);
510
511 return buf;
512 }
513
514 /* convert the hex array pointed to by buf into binary to be placed in mem
515 * return a pointer to the character AFTER the last byte written */
516
517 static char *
518 hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
519 {
520 int i;
521 unsigned char ch;
522
523 set_mem_fault_trap(may_fault);
524
525 for (i=0; i<count; i++)
526 {
527 ch = hex(*buf++) << 4;
528 ch |= hex(*buf++);
529 *mem++ = ch;
530 if (mem_err)
531 return 0;
532 }
533
534 set_mem_fault_trap(0);
535
536 return mem;
537 }
538
539 /* This table contains the mapping between SPARC hardware trap types, and
540 signals, which are primarily what GDB understands. It also indicates
541 which hardware traps we need to commandeer when initializing the stub. */
542
543 static struct hard_trap_info
544 {
545 unsigned char tt; /* Trap type code for SPARClite */
546 unsigned char signo; /* Signal that we map this trap into */
547 } hard_trap_info[] = {
548 {0x01, SIGSEGV}, /* instruction access error */
549 {0x02, SIGILL}, /* privileged instruction */
550 {0x03, SIGILL}, /* illegal instruction */
551 {0x04, SIGEMT}, /* fp disabled */
552 {0x07, SIGBUS}, /* mem address not aligned */
553 {0x09, SIGSEGV}, /* data access exception */
554 {0x0a, SIGEMT}, /* tag overflow */
555 {0x20, SIGBUS}, /* r register access error */
556 {0x21, SIGBUS}, /* instruction access error */
557 {0x24, SIGEMT}, /* cp disabled */
558 {0x29, SIGBUS}, /* data access error */
559 {0x2a, SIGFPE}, /* divide by zero */
560 {0x2b, SIGBUS}, /* data store error */
561 {0x80+1, SIGTRAP}, /* ta 1 - normal breakpoint instruction */
562 {0xff, SIGTRAP}, /* hardware breakpoint */
563 {0, 0} /* Must be last */
564 };
565
566 /* Set up exception handlers for tracing and breakpoints */
567
568 void
569 set_debug_traps (void)
570 {
571 struct hard_trap_info *ht;
572
573 /* Only setup fp traps if the FP is disabled. */
574
575 for (ht = hard_trap_info;
576 ht->tt != 0 && ht->signo != 0;
577 ht++)
578 if (ht->tt != 4 || ! (read_psr () & 0x1000))
579 exceptionHandler(ht->tt, trap_low);
580
581 initialized = 1;
582 }
583
584 asm ("
585 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
586 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
587 ! 0 would ever contain code that could mem fault. This routine will skip
588 ! past the faulting instruction after setting mem_err.
589
590 .text
591 .align 4
592
593 _fltr_set_mem_err:
594 sethi %hi(_mem_err), %l0
595 st %l1, [%l0 + %lo(_mem_err)]
596 jmpl %l2, %g0
597 rett %l2+4
598 ");
599
600 static void
601 set_mem_fault_trap (int enable)
602 {
603 extern void fltr_set_mem_err();
604 mem_err = 0;
605
606 if (enable)
607 exceptionHandler(9, fltr_set_mem_err);
608 else
609 exceptionHandler(9, trap_low);
610 }
611
612 asm ("
613 .text
614 .align 4
615
616 _dummy_hw_breakpoint:
617 jmpl %l2, %g0
618 rett %l2+4
619 nop
620 nop
621 ");
622
623 static void
624 get_in_break_mode (void)
625 {
626 extern void dummy_hw_breakpoint();
627
628 exceptionHandler (255, dummy_hw_breakpoint);
629
630 asm ("ta 255");
631
632 exceptionHandler (255, trap_low);
633 }
634
635 /* Convert the SPARC hardware trap type code to a unix signal number. */
636
637 static int
638 computeSignal (int tt)
639 {
640 struct hard_trap_info *ht;
641
642 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
643 if (ht->tt == tt)
644 return ht->signo;
645
646 return SIGHUP; /* default for things we don't know about */
647 }
648
649 /*
650 * While we find nice hex chars, build an int.
651 * Return number of chars processed.
652 */
653
654 static int
655 hexToInt(char **ptr, int *intValue)
656 {
657 int numChars = 0;
658 int hexValue;
659
660 *intValue = 0;
661
662 while (**ptr)
663 {
664 hexValue = hex(**ptr);
665 if (hexValue < 0)
666 break;
667
668 *intValue = (*intValue << 4) | hexValue;
669 numChars ++;
670
671 (*ptr)++;
672 }
673
674 return (numChars);
675 }
676
677 /*
678 * This function does all command procesing for interfacing to gdb. It
679 * returns 1 if you should skip the instruction at the trap address, 0
680 * otherwise.
681 */
682
683 static void
684 handle_exception (unsigned long *registers)
685 {
686 int tt; /* Trap type */
687 int sigval;
688 int addr;
689 int length;
690 char *ptr;
691 unsigned long *sp;
692 unsigned long dsr;
693
694 /* First, we must force all of the windows to be spilled out */
695
696 asm(" save %sp, -64, %sp
697 save %sp, -64, %sp
698 save %sp, -64, %sp
699 save %sp, -64, %sp
700 save %sp, -64, %sp
701 save %sp, -64, %sp
702 save %sp, -64, %sp
703 save %sp, -64, %sp
704 restore
705 restore
706 restore
707 restore
708 restore
709 restore
710 restore
711 restore
712 ");
713
714 get_in_break_mode (); /* Enable DSU register writes */
715
716 registers[DIA1] = read_asi (1, 0xff00);
717 registers[DIA2] = read_asi (1, 0xff04);
718 registers[DDA1] = read_asi (1, 0xff08);
719 registers[DDA2] = read_asi (1, 0xff0c);
720 registers[DDV1] = read_asi (1, 0xff10);
721 registers[DDV2] = read_asi (1, 0xff14);
722 registers[DCR] = read_asi (1, 0xff18);
723 registers[DSR] = read_asi (1, 0xff1c);
724
725 if (registers[PC] == (unsigned long)breakinst)
726 {
727 registers[PC] = registers[NPC];
728 registers[NPC] += 4;
729 }
730 sp = (unsigned long *)registers[SP];
731
732 dsr = (unsigned long)registers[DSR];
733 if (dsr & 0x3c)
734 tt = 255;
735 else
736 tt = (registers[TBR] >> 4) & 0xff;
737
738 /* reply to host that an exception has occurred */
739 sigval = computeSignal(tt);
740 ptr = remcomOutBuffer;
741
742 *ptr++ = 'T';
743 *ptr++ = hexchars[sigval >> 4];
744 *ptr++ = hexchars[sigval & 0xf];
745
746 *ptr++ = hexchars[PC >> 4];
747 *ptr++ = hexchars[PC & 0xf];
748 *ptr++ = ':';
749 ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
750 *ptr++ = ';';
751
752 *ptr++ = hexchars[FP >> 4];
753 *ptr++ = hexchars[FP & 0xf];
754 *ptr++ = ':';
755 ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
756 *ptr++ = ';';
757
758 *ptr++ = hexchars[SP >> 4];
759 *ptr++ = hexchars[SP & 0xf];
760 *ptr++ = ':';
761 ptr = mem2hex((char *)&sp, ptr, 4, 0);
762 *ptr++ = ';';
763
764 *ptr++ = hexchars[NPC >> 4];
765 *ptr++ = hexchars[NPC & 0xf];
766 *ptr++ = ':';
767 ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
768 *ptr++ = ';';
769
770 *ptr++ = hexchars[O7 >> 4];
771 *ptr++ = hexchars[O7 & 0xf];
772 *ptr++ = ':';
773 ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
774 *ptr++ = ';';
775
776 *ptr++ = 0;
777
778 putpacket(remcomOutBuffer);
779
780 while (1)
781 {
782 remcomOutBuffer[0] = 0;
783
784 ptr = getpacket();
785 switch (*ptr++)
786 {
787 case '?':
788 remcomOutBuffer[0] = 'S';
789 remcomOutBuffer[1] = hexchars[sigval >> 4];
790 remcomOutBuffer[2] = hexchars[sigval & 0xf];
791 remcomOutBuffer[3] = 0;
792 break;
793
794 case 'd':
795 /* toggle debug flag */
796 break;
797
798 case 'g': /* return the value of the CPU registers */
799 memcpy (&registers[L0], sp, 16 * 4); /* Copy L & I regs from stack */
800 mem2hex ((char *)registers, remcomOutBuffer, NUMREGBYTES, 0);
801 break;
802
803 case 'G': /* Set the value of all registers */
804 case 'P': /* Set the value of one register */
805 {
806 unsigned long *newsp, psr;
807
808 psr = registers[PSR];
809
810 if (ptr[-1] == 'P')
811 {
812 int regno;
813
814 if (hexToInt (&ptr, &regno)
815 && *ptr++ == '=')
816 if (regno >= L0 && regno <= I7)
817 hex2mem (ptr, sp + regno - L0, 4, 0);
818 else
819 hex2mem (ptr, (char *)&registers[regno], 4, 0);
820 else
821 {
822 strcpy (remcomOutBuffer, "E01");
823 break;
824 }
825 }
826 else
827 {
828 hex2mem (ptr, (char *)registers, NUMREGBYTES, 0);
829 memcpy (sp, &registers[L0], 16 * 4); /* Copy L & I regs to stack */
830 }
831
832 /* See if the stack pointer has moved. If so, then copy the saved
833 locals and ins to the new location. This keeps the window
834 overflow and underflow routines happy. */
835
836 newsp = (unsigned long *)registers[SP];
837 if (sp != newsp)
838 sp = memcpy(newsp, sp, 16 * 4);
839
840 /* Don't allow CWP to be modified. */
841
842 if (psr != registers[PSR])
843 registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
844
845 strcpy(remcomOutBuffer,"OK");
846 }
847 break;
848
849 case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
850 /* Try to read %x,%x. */
851
852 if (hexToInt(&ptr, &addr)
853 && *ptr++ == ','
854 && hexToInt(&ptr, &length))
855 {
856 if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
857 break;
858
859 strcpy (remcomOutBuffer, "E03");
860 }
861 else
862 strcpy(remcomOutBuffer,"E01");
863 break;
864
865 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
866 /* Try to read '%x,%x:'. */
867
868 if (hexToInt(&ptr, &addr)
869 && *ptr++ == ','
870 && hexToInt(&ptr, &length)
871 && *ptr++ == ':')
872 {
873 if (hex2mem(ptr, (char *)addr, length, 1))
874 strcpy(remcomOutBuffer, "OK");
875 else
876 strcpy(remcomOutBuffer, "E03");
877 }
878 else
879 strcpy(remcomOutBuffer, "E02");
880 break;
881
882 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
883 /* try to read optional parameter, pc unchanged if no parm */
884 if (hexToInt(&ptr, &addr))
885 {
886 registers[PC] = addr;
887 registers[NPC] = addr + 4;
888 }
889
890 /* Need to flush the instruction cache here, as we may have deposited a
891 breakpoint, and the icache probably has no way of knowing that a data ref to
892 some location may have changed something that is in the instruction cache.
893 */
894
895 flush_i_cache ();
896
897 if (!(registers[DSR] & 0x1) /* DSU enabled? */
898 && !(registers[DCR] & 0x200)) /* Are we in break state? */
899 { /* Yes, set the DSU regs */
900 write_asi (1, 0xff00, registers[DIA1]);
901 write_asi (1, 0xff04, registers[DIA2]);
902 write_asi (1, 0xff08, registers[DDA1]);
903 write_asi (1, 0xff0c, registers[DDA2]);
904 write_asi (1, 0xff10, registers[DDV1]);
905 write_asi (1, 0xff14, registers[DDV2]);
906 write_asi (1, 0xff1c, registers[DSR]);
907 write_asi (1, 0xff18, registers[DCR] | 0x200); /* Clear break */
908 }
909
910 return;
911
912 /* kill the program */
913 case 'k' : /* do nothing */
914 break;
915 #if 0
916 case 't': /* Test feature */
917 asm (" std %f30,[%sp]");
918 break;
919 #endif
920 case 'r': /* Reset */
921 asm ("call 0
922 nop ");
923 break;
924 } /* switch */
925
926 /* reply to the request */
927 putpacket(remcomOutBuffer);
928 }
929 }
930
931 /* This function will generate a breakpoint exception. It is used at the
932 beginning of a program to sync up with a debugger and can be used
933 otherwise as a quick means to stop program execution and "break" into
934 the debugger. */
935
936 void
937 breakpoint (void)
938 {
939 if (!initialized)
940 return;
941
942 asm(" .globl _breakinst
943
944 _breakinst: ta 1
945 ");
946 }
This page took 0.076195 seconds and 4 git commands to generate.