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