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