]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/sparcl-stub.c
* sparc-stub.c: add nop after 'bg good_wim'.
[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
92 /************************************************************************
93 *
94 * external low-level support routines
95 */
96
97 extern putDebugChar(); /* write a single character */
98 extern getDebugChar(); /* read and return a single char */
99
100 /************************************************************************/
101 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
102 /* at least NUMREGBYTES*2 are needed for register packets */
103 #define BUFMAX 2048
104
105 static int initialized = 0; /* !0 means we've been initialized */
106
107 extern void breakinst();
108 static void hw_breakpoint();
109 static void set_mem_fault_trap();
110 static void get_in_break_mode();
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 asm("
136 .reserve trapstack, 1000 * 4, \"bss\", 8
137
138 .data
139 .align 4
140
141 in_trap_handler:
142 .word 0
143
144 .text
145 .align 4
146
147 ! This function is called when any SPARC trap (except window overflow or
148 ! underflow) occurs. It makes sure that the invalid register window is still
149 ! available before jumping into C code. It will also restore the world if you
150 ! return from handle_exception.
151
152 .globl _trap_low
153 _trap_low:
154 mov %psr, %l0
155 mov %wim, %l3
156
157 srl %l3, %l0, %l4 ! wim >> cwp
158 cmp %l4, 1
159 bne window_fine ! Branch if not in the invalid window
160 nop
161
162 ! Handle window overflow
163
164 mov %g1, %l4 ! Save g1, we use it to hold the wim
165 srl %l3, 1, %g1 ! Rotate wim right
166 tst %g1
167 bg good_wim ! Branch if new wim is non-zero
168 nop
169
170 ! At this point, we need to bring a 1 into the high order bit of the wim.
171 ! Since we don't want to make any assumptions about the number of register
172 ! windows, we figure it out dynamically so as to setup the wim correctly.
173
174 not %g1 ! Fill g1 with ones
175 mov %g1, %wim ! Fill the wim with ones
176 nop
177 nop
178 nop
179 mov %wim, %g1 ! Read back the wim
180 inc %g1 ! Now g1 has 1 just to left of wim
181 srl %g1, 1, %g1 ! Now put 1 at top of wim
182 mov %g0, %wim ! Clear wim so that subsequent save
183 nop ! won't trap
184 nop
185 nop
186
187 good_wim:
188 save %g0, %g0, %g0 ! Slip into next window
189 mov %g1, %wim ! Install the new wim
190
191 std %l0, [%sp + 0 * 4] ! save L & I registers
192 std %l2, [%sp + 2 * 4]
193 std %l4, [%sp + 4 * 4]
194 std %l6, [%sp + 6 * 4]
195
196 std %i0, [%sp + 8 * 4]
197 std %i2, [%sp + 10 * 4]
198 std %i4, [%sp + 12 * 4]
199 std %i6, [%sp + 14 * 4]
200
201 restore ! Go back to trap window.
202 mov %l4, %g1 ! Restore %g1
203
204 window_fine:
205 sethi %hi(in_trap_handler), %l4
206 ld [%lo(in_trap_handler) + %l4], %l5
207 tst %l5
208 bg recursive_trap
209 inc %l5
210
211 set trapstack+1000*4, %sp ! Switch to trap stack
212
213 recursive_trap:
214 st %l5, [%lo(in_trap_handler) + %l4]
215 sub %sp,(16+1+6+1+80)*4,%sp ! Make room for input & locals
216 ! + hidden arg + arg spill
217 ! + doubleword alignment
218 ! + registers[72] local var
219
220 std %g0, [%sp + (24 + 0) * 4] ! registers[Gx]
221 std %g2, [%sp + (24 + 2) * 4]
222 std %g4, [%sp + (24 + 4) * 4]
223 std %g6, [%sp + (24 + 6) * 4]
224
225 std %i0, [%sp + (24 + 8) * 4] ! registers[Ox]
226 std %i2, [%sp + (24 + 10) * 4]
227 std %i4, [%sp + (24 + 12) * 4]
228 std %i6, [%sp + (24 + 14) * 4]
229 ! F0->F31 not implemented
230 mov %y, %l4
231 mov %tbr, %l5
232 st %l4, [%sp + (24 + 64) * 4] ! Y
233 st %l0, [%sp + (24 + 65) * 4] ! PSR
234 st %l3, [%sp + (24 + 66) * 4] ! WIM
235 st %l5, [%sp + (24 + 67) * 4] ! TBR
236 st %l1, [%sp + (24 + 68) * 4] ! PC
237 st %l2, [%sp + (24 + 69) * 4] ! NPC
238 ! CPSR and FPSR not impl
239 or %l0, 0xf20, %l4
240 mov %l4, %psr ! Turn on traps, disable interrupts
241 nop
242 nop
243 nop
244 call _get_in_break_mode
245 nop
246 nop
247 nop
248
249 sethi %hi(0xff00), %l5
250 or %l5, %lo(0xff00), %l5
251
252 lda [%l5]0x1, %l4
253 st %l4, [%sp + (24 + 72) * 4] ! DIA1, debug instr addr 1
254 add %l5, 4, %l5
255 lda [%l5]0x1, %l4
256 st %l4, [%sp + (24 + 73) * 4] ! DIA2, debug instr addr 2
257 add %l5, 4, %l5
258 lda [%l5]0x1, %l4
259 st %l4, [%sp + (24 + 74) * 4] ! DDA1, debug data addr 1
260 add %l5, 4, %l5
261 lda [%l5]0x1, %l4
262 st %l4, [%sp + (24 + 75) * 4] ! DDA2, debug data addr 2
263 add %l5, 4, %l5
264 lda [%l5]0x1, %l4
265 st %l4, [%sp + (24 + 76) * 4] ! DDV1, debug data val 1
266 add %l5, 4, %l5
267 lda [%l5]0x1, %l4
268 st %l4, [%sp + (24 + 77) * 4] ! DDV2, debug data val 2
269 add %l5, 4, %l5
270 lda [%l5]0x1, %l4
271 st %l4, [%sp + (24 + 78) * 4] ! DCR, debug control reg
272 add %l5, 4, %l5
273 lda [%l5]0x1, %l4
274 st %l4, [%sp + (24 + 79) * 4] ! DSR, debug status reg
275 nop
276 nop
277 or %l0, 0xf20, %l4
278 mov %l4, %psr ! Turn on traps, disable interrupts
279 nop
280 nop
281 nop
282 call _handle_exception
283 add %sp, 24 * 4, %o0 ! Pass address of registers
284
285 ! Reload all of the registers that aren't on the stack
286
287 ld [%sp + (24 + 1) * 4], %g1 ! registers[Gx]
288 ldd [%sp + (24 + 2) * 4], %g2
289 ldd [%sp + (24 + 4) * 4], %g4
290 ldd [%sp + (24 + 6) * 4], %g6
291
292 ldd [%sp + (24 + 8) * 4], %i0 ! registers[Ox]
293 ldd [%sp + (24 + 10) * 4], %i2
294 ldd [%sp + (24 + 12) * 4], %i4
295 ldd [%sp + (24 + 14) * 4], %i6
296
297 sethi %hi(0xff00), %l2
298 or %l2, %lo(0xff00), %l2
299 ldd [%sp + (24 + 72) * 4], %l4 ! DIA1, debug instr addr 1
300 stda %l4, [%l2]0x1
301 nop
302 nop
303 nop
304 nop
305 ldd [%sp + (24 + 74) * 4], %l4 ! DDA1, debug data addr 1
306 add %l2, 8, %l2
307 stda %l4, [%l2]0x1
308 nop
309 nop
310 nop
311 nop
312 ldd [%sp + (24 + 76) * 4], %l4 ! DDV1, debug data value 1
313 add %l2, 8, %l2
314 stda %l4, [%l2]0x1
315 nop
316 nop
317 nop
318 nop
319 ld [%sp + (24 + 78) * 4], %l4 ! DCR, debug control reg
320 ld [%sp + (24 + 79) * 4], %l5 ! DSR, debug control reg
321 add %l2, 8, %l2
322 or %l4, 0x200, %l4
323 sta %l4, [%l2]0x1
324 add %l2, 4, %l2
325 sta %l5, [%l2]0x1
326 nop
327 nop
328 nop
329 nop
330
331 ldd [%sp + (24 + 64) * 4], %l0 ! Y & PSR
332 ldd [%sp + (24 + 68) * 4], %l2 ! PC & NPC
333
334 restore ! Ensure that previous window is valid
335 save %g0, %g0, %g0 ! by causing a window_underflow trap
336
337 mov %l0, %y
338 mov %l1, %psr ! Make sure that traps are disabled
339 ! for rett
340 sethi %hi(in_trap_handler), %l4
341 ld [%lo(in_trap_handler) + %l4], %l5
342 dec %l5
343 st %l5, [%lo(in_trap_handler) + %l4]
344
345 jmpl %l2, %g0 ! Restore old PC
346 rett %l3 ! Restore old nPC
347 ");
348
349 /* Convert ch from a hex digit to an int */
350
351 static int
352 hex(ch)
353 unsigned char ch;
354 {
355 if (ch >= 'a' && ch <= 'f')
356 return ch-'a'+10;
357 if (ch >= '0' && ch <= '9')
358 return ch-'0';
359 if (ch >= 'A' && ch <= 'F')
360 return ch-'A'+10;
361 return -1;
362 }
363
364 /* scan for the sequence $<data>#<checksum> */
365
366 static void
367 getpacket(buffer)
368 char *buffer;
369 {
370 unsigned char checksum;
371 unsigned char xmitcsum;
372 int i;
373 int count;
374 unsigned char ch;
375
376 do
377 {
378 /* wait around for the start character, ignore all other characters */
379 while ((ch = (getDebugChar() & 0x7f)) != '$') ;
380
381 checksum = 0;
382 xmitcsum = -1;
383
384 count = 0;
385
386 /* now, read until a # or end of buffer is found */
387 while (count < BUFMAX)
388 {
389 ch = getDebugChar() & 0x7f;
390 if (ch == '#')
391 break;
392 checksum = checksum + ch;
393 buffer[count] = ch;
394 count = count + 1;
395 }
396
397 if (count >= BUFMAX)
398 continue;
399
400 buffer[count] = 0;
401
402 if (ch == '#')
403 {
404 xmitcsum = hex(getDebugChar() & 0x7f) << 4;
405 xmitcsum |= hex(getDebugChar() & 0x7f);
406 #if 0
407 /* Humans shouldn't have to figure out checksums to type to it. */
408 putDebugChar ('+');
409 return;
410 #endif
411 if (checksum != xmitcsum)
412 putDebugChar('-'); /* failed checksum */
413 else
414 {
415 putDebugChar('+'); /* successful transfer */
416 /* if a sequence char is present, reply the sequence ID */
417 if (buffer[2] == ':')
418 {
419 putDebugChar(buffer[0]);
420 putDebugChar(buffer[1]);
421 /* remove sequence chars from buffer */
422 count = strlen(buffer);
423 for (i=3; i <= count; i++)
424 buffer[i-3] = buffer[i];
425 }
426 }
427 }
428 }
429 while (checksum != xmitcsum);
430 }
431
432 /* send the packet in buffer. */
433
434 static void
435 putpacket(buffer)
436 unsigned char *buffer;
437 {
438 unsigned char checksum;
439 int count;
440 unsigned char ch;
441
442 /* $<packet info>#<checksum>. */
443 do
444 {
445 putDebugChar('$');
446 checksum = 0;
447 count = 0;
448
449 while (ch = buffer[count])
450 {
451 if (! putDebugChar(ch))
452 return;
453 checksum += ch;
454 count += 1;
455 }
456
457 putDebugChar('#');
458 putDebugChar(hexchars[checksum >> 4]);
459 putDebugChar(hexchars[checksum & 0xf]);
460
461 }
462 while ((getDebugChar() & 0x7f) != '+');
463 }
464
465 static char remcomInBuffer[BUFMAX];
466 static char remcomOutBuffer[BUFMAX];
467
468 /* Indicate to caller of mem2hex or hex2mem that there has been an
469 error. */
470 static volatile int mem_err = 0;
471
472 /* Convert the memory pointed to by mem into hex, placing result in buf.
473 * Return a pointer to the last char put in buf (null), in case of mem fault,
474 * return 0.
475 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
476 * a 0, else treat a fault like any other fault in the stub.
477 */
478
479 static unsigned char *
480 mem2hex(mem, buf, count, may_fault)
481 unsigned char *mem;
482 unsigned char *buf;
483 int count;
484 int may_fault;
485 {
486 unsigned char ch;
487
488 set_mem_fault_trap(may_fault);
489
490 while (count-- > 0)
491 {
492 ch = *mem++;
493 if (mem_err)
494 return 0;
495 *buf++ = hexchars[ch >> 4];
496 *buf++ = hexchars[ch & 0xf];
497 }
498
499 *buf = 0;
500
501 set_mem_fault_trap(0);
502
503 return buf;
504 }
505
506 /* convert the hex array pointed to by buf into binary to be placed in mem
507 * return a pointer to the character AFTER the last byte written */
508
509 static char *
510 hex2mem(buf, mem, count, may_fault)
511 unsigned char *buf;
512 unsigned char *mem;
513 int count;
514 int may_fault;
515 {
516 int i;
517 unsigned char ch;
518
519 set_mem_fault_trap(may_fault);
520
521 for (i=0; i<count; i++)
522 {
523 ch = hex(*buf++) << 4;
524 ch |= hex(*buf++);
525 *mem++ = ch;
526 if (mem_err)
527 return 0;
528 }
529
530 set_mem_fault_trap(0);
531
532 return mem;
533 }
534
535 /* This table contains the mapping between SPARC hardware trap types, and
536 signals, which are primarily what GDB understands. It also indicates
537 which hardware traps we need to commandeer when initializing the stub. */
538
539 static struct hard_trap_info
540 {
541 unsigned char tt; /* Trap type code for SPARClite */
542 unsigned char signo; /* Signal that we map this trap into */
543 } hard_trap_info[] = {
544 {1, SIGSEGV}, /* instruction access error */
545 {2, SIGILL}, /* privileged instruction */
546 {3, SIGILL}, /* illegal instruction */
547 {4, SIGEMT}, /* fp disabled */
548 {36, SIGEMT}, /* cp disabled */
549 {7, SIGBUS}, /* mem address not aligned */
550 {9, SIGSEGV}, /* data access exception */
551 {10, SIGEMT}, /* tag overflow */
552 {128+1, SIGTRAP}, /* ta 1 - normal breakpoint instruction */
553 {255, SIGTRAP}, /* hardware breakpoint */
554 {0, 0} /* Must be last */
555 };
556
557 /* Set up exception handlers for tracing and breakpoints */
558
559 void
560 set_debug_traps()
561 {
562 struct hard_trap_info *ht;
563
564 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
565 exceptionHandler(ht->tt, trap_low);
566
567 /* In case GDB is started before us, ack any packets (presumably
568 "$?#xx") sitting there. */
569
570 putDebugChar ('+');
571
572 initialized = 1;
573 }
574
575 asm ("
576 ! Trap handler for memory errors. This just sets mem_err to be non-zero. It
577 ! assumes that %l1 is non-zero. This should be safe, as it is doubtful that
578 ! 0 would ever contain code that could mem fault. This routine will skip
579 ! past the faulting instruction after setting mem_err.
580
581 .text
582 .align 4
583
584 _fltr_set_mem_err:
585 sethi %hi(_mem_err), %l0
586 st %l1, [%l0 + %lo(_mem_err)]
587 jmpl %l2, %g0
588 rett %l2+4
589 ");
590
591 static void
592 set_mem_fault_trap(enable)
593 int enable;
594 {
595 extern void fltr_set_mem_err();
596 mem_err = 0;
597
598 if (enable)
599 exceptionHandler(9, fltr_set_mem_err);
600 else
601 exceptionHandler(9, trap_low);
602 }
603
604 asm ("
605 .text
606 .align 4
607
608 _dummy_hw_breakpoint:
609 jmpl %l2, %g0
610 rett %l2+4
611 nop
612 nop
613 ");
614
615 static void
616 set_hw_breakpoint_trap(enable)
617 int enable;
618 {
619 extern void dummy_hw_breakpoint();
620
621 if (enable)
622 exceptionHandler(255, dummy_hw_breakpoint);
623 else
624 exceptionHandler(255, trap_low);
625 }
626
627 static void
628 get_in_break_mode()
629 {
630 set_hw_breakpoint_trap(1);
631
632 asm("
633 sethi %hi(0xff10), %l4
634 or %l4, %lo(0xff10), %l4
635 sta %g0, [%l4]0x1
636 nop
637 nop
638 nop
639 ");
640
641 set_hw_breakpoint_trap(0);
642 }
643
644 /* Convert the SPARC hardware trap type code to a unix signal number. */
645
646 static int
647 computeSignal(tt)
648 int tt;
649 {
650 struct hard_trap_info *ht;
651
652 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
653 if (ht->tt == tt)
654 return ht->signo;
655
656 return SIGHUP; /* default for things we don't know about */
657 }
658
659 /*
660 * While we find nice hex chars, build an int.
661 * Return number of chars processed.
662 */
663
664 static int
665 hexToInt(char **ptr, int *intValue)
666 {
667 int numChars = 0;
668 int hexValue;
669
670 *intValue = 0;
671
672 while (**ptr)
673 {
674 hexValue = hex(**ptr);
675 if (hexValue < 0)
676 break;
677
678 *intValue = (*intValue << 4) | hexValue;
679 numChars ++;
680
681 (*ptr)++;
682 }
683
684 return (numChars);
685 }
686
687 /*
688 * This function does all command procesing for interfacing to gdb. It
689 * returns 1 if you should skip the instruction at the trap address, 0
690 * otherwise.
691 */
692
693
694 static void
695 handle_exception (registers)
696 unsigned long *registers;
697 {
698 int tt; /* Trap type */
699 int sigval;
700 int addr;
701 int length;
702 char *ptr;
703 unsigned long *sp;
704 unsigned long dsr;
705
706 /* First, we must force all of the windows to be spilled out */
707
708 asm(" save %sp, -64, %sp
709 save %sp, -64, %sp
710 save %sp, -64, %sp
711 save %sp, -64, %sp
712 save %sp, -64, %sp
713 save %sp, -64, %sp
714 save %sp, -64, %sp
715 save %sp, -64, %sp
716 restore
717 restore
718 restore
719 restore
720 restore
721 restore
722 restore
723 restore
724 ");
725
726 if (registers[PC] == (unsigned long)breakinst)
727 {
728 registers[PC] = registers[NPC];
729 registers[NPC] += 4;
730 }
731 sp = (unsigned long *)registers[SP];
732
733 dsr = (unsigned long)registers[DSR];
734 if (dsr & 0x3c)
735 {
736 tt = 255;
737 }
738 else
739 {
740 tt = (registers[TBR] >> 4) & 0xff;
741 }
742
743 /* reply to host that an exception has occurred */
744 sigval = computeSignal(tt);
745 ptr = remcomOutBuffer;
746
747 *ptr++ = 'T';
748 *ptr++ = hexchars[sigval >> 4];
749 *ptr++ = hexchars[sigval & 0xf];
750
751 *ptr++ = hexchars[PC >> 4];
752 *ptr++ = hexchars[PC & 0xf];
753 *ptr++ = ':';
754 ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
755 *ptr++ = ';';
756
757 *ptr++ = hexchars[FP >> 4];
758 *ptr++ = hexchars[FP & 0xf];
759 *ptr++ = ':';
760 ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
761 *ptr++ = ';';
762
763 *ptr++ = hexchars[SP >> 4];
764 *ptr++ = hexchars[SP & 0xf];
765 *ptr++ = ':';
766 ptr = mem2hex((char *)&sp, ptr, 4, 0);
767 *ptr++ = ';';
768
769 *ptr++ = hexchars[NPC >> 4];
770 *ptr++ = hexchars[NPC & 0xf];
771 *ptr++ = ':';
772 ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
773 *ptr++ = ';';
774
775 *ptr++ = hexchars[O7 >> 4];
776 *ptr++ = hexchars[O7 & 0xf];
777 *ptr++ = ':';
778 ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
779 *ptr++ = ';';
780
781 *ptr++ = 0;
782
783 putpacket(remcomOutBuffer);
784
785 while (1)
786 {
787 remcomOutBuffer[0] = 0;
788
789 getpacket(remcomInBuffer);
790 switch (remcomInBuffer[0])
791 {
792 case '?':
793 remcomOutBuffer[0] = 'S';
794 remcomOutBuffer[1] = hexchars[sigval >> 4];
795 remcomOutBuffer[2] = hexchars[sigval & 0xf];
796 remcomOutBuffer[3] = 0;
797 break;
798
799 case 'd':
800 /* toggle debug flag */
801 break;
802
803 case 'g': /* return the value of the CPU registers */
804 {
805 ptr = remcomOutBuffer;
806 ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
807 ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
808 memset(ptr, '0', 32 * 8); /* Floating point */
809 ptr = mem2hex((char *)&registers[Y],
810 ptr + 32 * 4 * 2,
811 8 * 4,
812 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
813 mem2hex((char *)&registers[DIA1], ptr,
814 8 * 4, 0); /* DIA1, DIA2, DDA1, DDA2, DDV1, DDV2, DCR, DSR */
815 }
816 break;
817
818 case 'G': /* set the value of the CPU registers - return OK */
819 {
820 unsigned long *newsp, psr;
821
822 psr = registers[PSR];
823
824 ptr = &remcomInBuffer[1];
825 hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
826 hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
827 hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y],
828 8 * 4, 0); /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
829 hex2mem(ptr + 72 * 4 * 2, (char *)&registers[DIA1],
830 8 * 4, 0); /* DIA1, DIA2, DDA1, DDA2, DDV1, DDV2, DCR, DSR */
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 ptr = &remcomInBuffer[1];
853
854 if (hexToInt(&ptr, &addr)
855 && *ptr++ == ','
856 && hexToInt(&ptr, &length))
857 {
858 if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
859 break;
860
861 strcpy (remcomOutBuffer, "E03");
862 }
863 else
864 strcpy(remcomOutBuffer,"E01");
865 break;
866
867 case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
868 /* Try to read '%x,%x:'. */
869
870 ptr = &remcomInBuffer[1];
871
872 if (hexToInt(&ptr, &addr)
873 && *ptr++ == ','
874 && hexToInt(&ptr, &length)
875 && *ptr++ == ':')
876 {
877 if (hex2mem(ptr, (char *)addr, length, 1))
878 strcpy(remcomOutBuffer, "OK");
879 else
880 strcpy(remcomOutBuffer, "E03");
881 }
882 else
883 strcpy(remcomOutBuffer, "E02");
884 break;
885
886 case 'c': /* cAA..AA Continue at address AA..AA(optional) */
887 /* try to read optional parameter, pc unchanged if no parm */
888
889 ptr = &remcomInBuffer[1];
890 if (hexToInt(&ptr, &addr))
891 {
892 registers[PC] = addr;
893 registers[NPC] = addr + 4;
894 }
895
896 /* Need to flush the instruction cache here, as we may have deposited a
897 breakpoint, and the icache probably has no way of knowing that a data ref to
898 some location may have changed something that is in the instruction cache.
899 */
900
901 flush_i_cache();
902 return;
903
904 /* kill the program */
905 case 'k' : /* do nothing */
906 break;
907 #if 0
908 case 't': /* Test feature */
909 asm (" std %f30,[%sp]");
910 break;
911 #endif
912 case 'r': /* Reset */
913 asm ("call 0
914 nop ");
915 break;
916
917 #if 0
918 Disabled until we can unscrew this properly
919
920 case 'b': /* bBB... Set baud rate to BB... */
921 {
922 int baudrate;
923 extern void set_timer_3();
924
925 ptr = &remcomInBuffer[1];
926 if (!hexToInt(&ptr, &baudrate))
927 {
928 strcpy(remcomOutBuffer,"B01");
929 break;
930 }
931
932 /* Convert baud rate to uart clock divider */
933 switch (baudrate)
934 {
935 case 38400:
936 baudrate = 16;
937 break;
938 case 19200:
939 baudrate = 33;
940 break;
941 case 9600:
942 baudrate = 65;
943 break;
944 default:
945 strcpy(remcomOutBuffer,"B02");
946 goto x1;
947 }
948
949 putpacket("OK"); /* Ack before changing speed */
950 set_timer_3(baudrate); /* Set it */
951 }
952 x1: break;
953 #endif
954 } /* switch */
955
956 /* reply to the request */
957 putpacket(remcomOutBuffer);
958 }
959 }
960
961 /* This function will generate a breakpoint exception. It is used at the
962 beginning of a program to sync up with a debugger and can be used
963 otherwise as a quick means to stop program execution and "break" into
964 the debugger. */
965
966 void
967 breakpoint()
968 {
969 if (!initialized)
970 return;
971
972 asm(" .globl _breakinst
973
974 _breakinst: ta 1
975 ");
976 }
977
978 static void
979 hw_breakpoint()
980 {
981 asm("
982 ta 127
983 ");
984 }