Home | History | Annotate | Line # | Download | only in stubs
sparc-stub.c revision 1.1.1.2
      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  *
     34  *  This code has been extensively tested on the Fujitsu SPARClite demo board.
     35  *
     36  *  To enable debugger support, two things need to happen.  One, a
     37  *  call to set_debug_traps() is necessary in order to allow any breakpoints
     38  *  or error conditions to be properly intercepted and reported to gdb.
     39  *  Two, a breakpoint needs to be generated to begin communication.  This
     40  *  is most easily accomplished by a call to breakpoint().  Breakpoint()
     41  *  simulates a breakpoint by executing a trap #1.
     42  *
     43  *************
     44  *
     45  *    The following gdb commands are supported:
     46  *
     47  * command          function                               Return value
     48  *
     49  *    g             return the value of the CPU registers  hex data or ENN
     50  *    G             set the value of the CPU registers     OK or ENN
     51  *
     52  *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
     53  *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
     54  *
     55  *    c             Resume at current address              SNN   ( signal NN)
     56  *    cAA..AA       Continue at address AA..AA             SNN
     57  *
     58  *    s             Step one instruction                   SNN
     59  *    sAA..AA       Step one instruction from AA..AA       SNN
     60  *
     61  *    k             kill
     62  *
     63  *    ?             What was the last sigval ?             SNN   (signal NN)
     64  *
     65  * All commands and responses are sent with a packet which includes a
     66  * checksum.  A packet consists of
     67  *
     68  * $<packet info>#<checksum>.
     69  *
     70  * where
     71  * <packet info> :: <characters representing the command or response>
     72  * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
     73  *
     74  * When a packet is received, it is first acknowledged with either '+' or '-'.
     75  * '+' indicates a successful transfer.  '-' indicates a failed transfer.
     76  *
     77  * Example:
     78  *
     79  * Host:                  Reply:
     80  * $m0,10#2a               +$00010203040506070809101112131415#42
     81  *
     82  ****************************************************************************/
     83 
     84 #include <string.h>
     85 #include <signal.h>
     86 
     87 /************************************************************************
     88  *
     89  * external low-level support routines
     90  */
     91 
     92 extern void putDebugChar();	/* write a single character      */
     93 extern int getDebugChar();	/* read and return a single char */
     94 
     95 /************************************************************************/
     96 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
     97 /* at least NUMREGBYTES*2 are needed for register packets */
     98 #define BUFMAX 2048
     99 
    100 static int initialized = 0;	/* !0 means we've been initialized */
    101 
    102 static void set_mem_fault_trap();
    103 
    104 static const char hexchars[]="0123456789abcdef";
    105 
    106 #define NUMREGS 72
    107 
    108 /* Number of bytes of registers.  */
    109 #define NUMREGBYTES (NUMREGS * 4)
    110 enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
    111 		 O0, O1, O2, O3, O4, O5, SP, O7,
    112 		 L0, L1, L2, L3, L4, L5, L6, L7,
    113 		 I0, I1, I2, I3, I4, I5, FP, I7,
    114 
    115 		 F0, F1, F2, F3, F4, F5, F6, F7,
    116 		 F8, F9, F10, F11, F12, F13, F14, F15,
    117 		 F16, F17, F18, F19, F20, F21, F22, F23,
    118 		 F24, F25, F26, F27, F28, F29, F30, F31,
    119 		 Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR };
    120 
    121 /***************************  ASSEMBLY CODE MACROS *************************/
    122 /* 									   */
    123 
    124 extern void trap_low();
    125 
    126 asm("
    127 	.reserve trapstack, 1000 * 4, \"bss\", 8
    128 
    129 	.data
    130 	.align	4
    131 
    132 in_trap_handler:
    133 	.word	0
    134 
    135 	.text
    136 	.align 4
    137 
    138 ! This function is called when any SPARC trap (except window overflow or
    139 ! underflow) occurs.  It makes sure that the invalid register window is still
    140 ! available before jumping into C code.  It will also restore the world if you
    141 ! return from handle_exception.
    142 
    143 	.globl _trap_low
    144 _trap_low:
    145 	mov	%psr, %l0
    146 	mov	%wim, %l3
    147 
    148 	srl	%l3, %l0, %l4		! wim >> cwp
    149 	cmp	%l4, 1
    150 	bne	window_fine		! Branch if not in the invalid window
    151 	nop
    152 
    153 ! Handle window overflow
    154 
    155 	mov	%g1, %l4		! Save g1, we use it to hold the wim
    156 	srl	%l3, 1, %g1		! Rotate wim right
    157 	tst	%g1
    158 	bg	good_wim		! Branch if new wim is non-zero
    159 	nop
    160 
    161 ! At this point, we need to bring a 1 into the high order bit of the wim.
    162 ! Since we don't want to make any assumptions about the number of register
    163 ! windows, we figure it out dynamically so as to setup the wim correctly.
    164 
    165 	not	%g1			! Fill g1 with ones
    166 	mov	%g1, %wim		! Fill the wim with ones
    167 	nop
    168 	nop
    169 	nop
    170 	mov	%wim, %g1		! Read back the wim
    171 	inc	%g1			! Now g1 has 1 just to left of wim
    172 	srl	%g1, 1, %g1		! Now put 1 at top of wim
    173 	mov	%g0, %wim		! Clear wim so that subsequent save
    174 	nop				!  won't trap
    175 	nop
    176 	nop
    177 
    178 good_wim:
    179 	save	%g0, %g0, %g0		! Slip into next window
    180 	mov	%g1, %wim		! Install the new wim
    181 
    182 	std	%l0, [%sp + 0 * 4]	! save L & I registers
    183 	std	%l2, [%sp + 2 * 4]
    184 	std	%l4, [%sp + 4 * 4]
    185 	std	%l6, [%sp + 6 * 4]
    186 
    187 	std	%i0, [%sp + 8 * 4]
    188 	std	%i2, [%sp + 10 * 4]
    189 	std	%i4, [%sp + 12 * 4]
    190 	std	%i6, [%sp + 14 * 4]
    191 
    192 	restore				! Go back to trap window.
    193 	mov	%l4, %g1		! Restore %g1
    194 
    195 window_fine:
    196 	sethi	%hi(in_trap_handler), %l4
    197 	ld	[%lo(in_trap_handler) + %l4], %l5
    198 	tst	%l5
    199 	bg	recursive_trap
    200 	inc	%l5
    201 
    202 	set	trapstack+1000*4, %sp	! Switch to trap stack
    203 
    204 recursive_trap:
    205 	st	%l5, [%lo(in_trap_handler) + %l4]
    206 	sub	%sp,(16+1+6+1+72)*4,%sp	! Make room for input & locals
    207 					! + hidden arg + arg spill
    208 					! + doubleword alignment
    209 					! + registers[72] local var
    210 
    211 	std	%g0, [%sp + (24 + 0) * 4] ! registers[Gx]
    212 	std	%g2, [%sp + (24 + 2) * 4]
    213 	std	%g4, [%sp + (24 + 4) * 4]
    214 	std	%g6, [%sp + (24 + 6) * 4]
    215 
    216 	std	%i0, [%sp + (24 + 8) * 4] ! registers[Ox]
    217 	std	%i2, [%sp + (24 + 10) * 4]
    218 	std	%i4, [%sp + (24 + 12) * 4]
    219 	std	%i6, [%sp + (24 + 14) * 4]
    220 					! F0->F31 not implemented
    221 	mov	%y, %l4
    222 	mov	%tbr, %l5
    223 	st	%l4, [%sp + (24 + 64) * 4] ! Y
    224 	st	%l0, [%sp + (24 + 65) * 4] ! PSR
    225 	st	%l3, [%sp + (24 + 66) * 4] ! WIM
    226 	st	%l5, [%sp + (24 + 67) * 4] ! TBR
    227 	st	%l1, [%sp + (24 + 68) * 4] ! PC
    228 	st	%l2, [%sp + (24 + 69) * 4] ! NPC
    229 
    230 					! CPSR and FPSR not impl
    231 
    232 	or	%l0, 0xf20, %l4
    233 	mov	%l4, %psr		! Turn on traps, disable interrupts
    234 
    235 	call	_handle_exception
    236 	add	%sp, 24 * 4, %o0	! Pass address of registers
    237 
    238 ! Reload all of the registers that aren't on the stack
    239 
    240 	ld	[%sp + (24 + 1) * 4], %g1 ! registers[Gx]
    241 	ldd	[%sp + (24 + 2) * 4], %g2
    242 	ldd	[%sp + (24 + 4) * 4], %g4
    243 	ldd	[%sp + (24 + 6) * 4], %g6
    244 
    245 	ldd	[%sp + (24 + 8) * 4], %i0 ! registers[Ox]
    246 	ldd	[%sp + (24 + 10) * 4], %i2
    247 	ldd	[%sp + (24 + 12) * 4], %i4
    248 	ldd	[%sp + (24 + 14) * 4], %i6
    249 
    250 	ldd	[%sp + (24 + 64) * 4], %l0 ! Y & PSR
    251 	ldd	[%sp + (24 + 68) * 4], %l2 ! PC & NPC
    252 
    253 	restore				! Ensure that previous window is valid
    254 	save	%g0, %g0, %g0		!  by causing a window_underflow trap
    255 
    256 	mov	%l0, %y
    257 	mov	%l1, %psr		! Make sure that traps are disabled
    258 					! for rett
    259 
    260 	sethi	%hi(in_trap_handler), %l4
    261 	ld	[%lo(in_trap_handler) + %l4], %l5
    262 	dec	%l5
    263 	st	%l5, [%lo(in_trap_handler) + %l4]
    264 
    265 	jmpl	%l2, %g0		! Restore old PC
    266 	rett	%l3			! Restore old nPC
    267 ");
    268 
    269 /* Convert ch from a hex digit to an int */
    270 
    271 static int
    272 hex (unsigned char ch)
    273 {
    274   if (ch >= 'a' && ch <= 'f')
    275     return ch-'a'+10;
    276   if (ch >= '0' && ch <= '9')
    277     return ch-'0';
    278   if (ch >= 'A' && ch <= 'F')
    279     return ch-'A'+10;
    280   return -1;
    281 }
    282 
    283 static char remcomInBuffer[BUFMAX];
    284 static char remcomOutBuffer[BUFMAX];
    285 
    286 /* scan for the sequence $<data>#<checksum>     */
    287 
    288 unsigned char *
    289 getpacket (void)
    290 {
    291   unsigned char *buffer = &remcomInBuffer[0];
    292   unsigned char checksum;
    293   unsigned char xmitcsum;
    294   int count;
    295   char ch;
    296 
    297   while (1)
    298     {
    299       /* wait around for the start character, ignore all other characters */
    300       while ((ch = getDebugChar ()) != '$')
    301 	;
    302 
    303 retry:
    304       checksum = 0;
    305       xmitcsum = -1;
    306       count = 0;
    307 
    308       /* now, read until a # or end of buffer is found */
    309       while (count < BUFMAX - 1)
    310 	{
    311 	  ch = getDebugChar ();
    312 	  if (ch == '$')
    313 	    goto retry;
    314 	  if (ch == '#')
    315 	    break;
    316 	  checksum = checksum + ch;
    317 	  buffer[count] = ch;
    318 	  count = count + 1;
    319 	}
    320       buffer[count] = 0;
    321 
    322       if (ch == '#')
    323 	{
    324 	  ch = getDebugChar ();
    325 	  xmitcsum = hex (ch) << 4;
    326 	  ch = getDebugChar ();
    327 	  xmitcsum += hex (ch);
    328 
    329 	  if (checksum != xmitcsum)
    330 	    {
    331 	      putDebugChar ('-');	/* failed checksum */
    332 	    }
    333 	  else
    334 	    {
    335 	      putDebugChar ('+');	/* successful transfer */
    336 
    337 	      /* if a sequence char is present, reply the sequence ID */
    338 	      if (buffer[2] == ':')
    339 		{
    340 		  putDebugChar (buffer[0]);
    341 		  putDebugChar (buffer[1]);
    342 
    343 		  return &buffer[3];
    344 		}
    345 
    346 	      return &buffer[0];
    347 	    }
    348 	}
    349     }
    350 }
    351 
    352 /* send the packet in buffer.  */
    353 
    354 static void
    355 putpacket (unsigned char *buffer)
    356 {
    357   unsigned char checksum;
    358   int count;
    359   unsigned char ch;
    360 
    361   /*  $<packet info>#<checksum>. */
    362   do
    363     {
    364       putDebugChar('$');
    365       checksum = 0;
    366       count = 0;
    367 
    368       while (ch = buffer[count])
    369 	{
    370 	  putDebugChar(ch);
    371 	  checksum += ch;
    372 	  count += 1;
    373 	}
    374 
    375       putDebugChar('#');
    376       putDebugChar(hexchars[checksum >> 4]);
    377       putDebugChar(hexchars[checksum & 0xf]);
    378 
    379     }
    380   while (getDebugChar() != '+');
    381 }
    382 
    383 /* Indicate to caller of mem2hex or hex2mem that there has been an
    384    error.  */
    385 static volatile int mem_err = 0;
    386 
    387 /* Convert the memory pointed to by mem into hex, placing result in buf.
    388  * Return a pointer to the last char put in buf (null), in case of mem fault,
    389  * return 0.
    390  * If MAY_FAULT is non-zero, then we will handle memory faults by returning
    391  * a 0, else treat a fault like any other fault in the stub.
    392  */
    393 
    394 static unsigned char *
    395 mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault)
    396 {
    397   unsigned char ch;
    398 
    399   set_mem_fault_trap(may_fault);
    400 
    401   while (count-- > 0)
    402     {
    403       ch = *mem++;
    404       if (mem_err)
    405 	return 0;
    406       *buf++ = hexchars[ch >> 4];
    407       *buf++ = hexchars[ch & 0xf];
    408     }
    409 
    410   *buf = 0;
    411 
    412   set_mem_fault_trap(0);
    413 
    414   return buf;
    415 }
    416 
    417 /* convert the hex array pointed to by buf into binary to be placed in mem
    418  * return a pointer to the character AFTER the last byte written */
    419 
    420 static char *
    421 hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
    422 {
    423   int i;
    424   unsigned char ch;
    425 
    426   set_mem_fault_trap(may_fault);
    427 
    428   for (i=0; i<count; i++)
    429     {
    430       ch = hex(*buf++) << 4;
    431       ch |= hex(*buf++);
    432       *mem++ = ch;
    433       if (mem_err)
    434 	return 0;
    435     }
    436 
    437   set_mem_fault_trap(0);
    438 
    439   return mem;
    440 }
    441 
    442 /* This table contains the mapping between SPARC hardware trap types, and
    443    signals, which are primarily what GDB understands.  It also indicates
    444    which hardware traps we need to commandeer when initializing the stub. */
    445 
    446 static struct hard_trap_info
    447 {
    448   unsigned char tt;		/* Trap type code for SPARClite */
    449   unsigned char signo;		/* Signal that we map this trap into */
    450 } hard_trap_info[] = {
    451   {1, SIGSEGV},			/* instruction access error */
    452   {2, SIGILL},			/* privileged instruction */
    453   {3, SIGILL},			/* illegal instruction */
    454   {4, SIGEMT},			/* fp disabled */
    455   {36, SIGEMT},			/* cp disabled */
    456   {7, SIGBUS},			/* mem address not aligned */
    457   {9, SIGSEGV},			/* data access exception */
    458   {10, SIGEMT},			/* tag overflow */
    459   {128+1, SIGTRAP},		/* ta 1 - normal breakpoint instruction */
    460   {0, 0}			/* Must be last */
    461 };
    462 
    463 /* Set up exception handlers for tracing and breakpoints */
    464 
    465 void
    466 set_debug_traps (void)
    467 {
    468   struct hard_trap_info *ht;
    469 
    470   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
    471     exceptionHandler(ht->tt, trap_low);
    472 
    473   initialized = 1;
    474 }
    475 
    476 asm ("
    477 ! Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
    478 ! assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
    479 ! 0 would ever contain code that could mem fault.  This routine will skip
    480 ! past the faulting instruction after setting mem_err.
    481 
    482 	.text
    483 	.align 4
    484 
    485 _fltr_set_mem_err:
    486 	sethi %hi(_mem_err), %l0
    487 	st %l1, [%l0 + %lo(_mem_err)]
    488 	jmpl %l2, %g0
    489 	rett %l2+4
    490 ");
    491 
    492 static void
    493 set_mem_fault_trap (int enable)
    494 {
    495   extern void fltr_set_mem_err();
    496   mem_err = 0;
    497 
    498   if (enable)
    499     exceptionHandler(9, fltr_set_mem_err);
    500   else
    501     exceptionHandler(9, trap_low);
    502 }
    503 
    504 /* Convert the SPARC hardware trap type code to a unix signal number. */
    505 
    506 static int
    507 computeSignal (int tt)
    508 {
    509   struct hard_trap_info *ht;
    510 
    511   for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
    512     if (ht->tt == tt)
    513       return ht->signo;
    514 
    515   return SIGHUP;		/* default for things we don't know about */
    516 }
    517 
    518 /*
    519  * While we find nice hex chars, build an int.
    520  * Return number of chars processed.
    521  */
    522 
    523 static int
    524 hexToInt(char **ptr, int *intValue)
    525 {
    526   int numChars = 0;
    527   int hexValue;
    528 
    529   *intValue = 0;
    530 
    531   while (**ptr)
    532     {
    533       hexValue = hex(**ptr);
    534       if (hexValue < 0)
    535 	break;
    536 
    537       *intValue = (*intValue << 4) | hexValue;
    538       numChars ++;
    539 
    540       (*ptr)++;
    541     }
    542 
    543   return (numChars);
    544 }
    545 
    546 /*
    547  * This function does all command procesing for interfacing to gdb.  It
    548  * returns 1 if you should skip the instruction at the trap address, 0
    549  * otherwise.
    550  */
    551 
    552 extern void breakinst();
    553 
    554 static void
    555 handle_exception (unsigned long *registers)
    556 {
    557   int tt;			/* Trap type */
    558   int sigval;
    559   int addr;
    560   int length;
    561   char *ptr;
    562   unsigned long *sp;
    563 
    564 /* First, we must force all of the windows to be spilled out */
    565 
    566   asm("	save %sp, -64, %sp
    567 	save %sp, -64, %sp
    568 	save %sp, -64, %sp
    569 	save %sp, -64, %sp
    570 	save %sp, -64, %sp
    571 	save %sp, -64, %sp
    572 	save %sp, -64, %sp
    573 	save %sp, -64, %sp
    574 	restore
    575 	restore
    576 	restore
    577 	restore
    578 	restore
    579 	restore
    580 	restore
    581 	restore
    582 ");
    583 
    584   if (registers[PC] == (unsigned long)breakinst)
    585     {
    586       registers[PC] = registers[NPC];
    587       registers[NPC] += 4;
    588     }
    589 
    590   sp = (unsigned long *)registers[SP];
    591 
    592   tt = (registers[TBR] >> 4) & 0xff;
    593 
    594   /* reply to host that an exception has occurred */
    595   sigval = computeSignal(tt);
    596   ptr = remcomOutBuffer;
    597 
    598   *ptr++ = 'T';
    599   *ptr++ = hexchars[sigval >> 4];
    600   *ptr++ = hexchars[sigval & 0xf];
    601 
    602   *ptr++ = hexchars[PC >> 4];
    603   *ptr++ = hexchars[PC & 0xf];
    604   *ptr++ = ':';
    605   ptr = mem2hex((char *)&registers[PC], ptr, 4, 0);
    606   *ptr++ = ';';
    607 
    608   *ptr++ = hexchars[FP >> 4];
    609   *ptr++ = hexchars[FP & 0xf];
    610   *ptr++ = ':';
    611   ptr = mem2hex(sp + 8 + 6, ptr, 4, 0); /* FP */
    612   *ptr++ = ';';
    613 
    614   *ptr++ = hexchars[SP >> 4];
    615   *ptr++ = hexchars[SP & 0xf];
    616   *ptr++ = ':';
    617   ptr = mem2hex((char *)&sp, ptr, 4, 0);
    618   *ptr++ = ';';
    619 
    620   *ptr++ = hexchars[NPC >> 4];
    621   *ptr++ = hexchars[NPC & 0xf];
    622   *ptr++ = ':';
    623   ptr = mem2hex((char *)&registers[NPC], ptr, 4, 0);
    624   *ptr++ = ';';
    625 
    626   *ptr++ = hexchars[O7 >> 4];
    627   *ptr++ = hexchars[O7 & 0xf];
    628   *ptr++ = ':';
    629   ptr = mem2hex((char *)&registers[O7], ptr, 4, 0);
    630   *ptr++ = ';';
    631 
    632   *ptr++ = 0;
    633 
    634   putpacket(remcomOutBuffer);
    635 
    636   while (1)
    637     {
    638       remcomOutBuffer[0] = 0;
    639 
    640       ptr = getpacket();
    641       switch (*ptr++)
    642 	{
    643 	case '?':
    644 	  remcomOutBuffer[0] = 'S';
    645 	  remcomOutBuffer[1] = hexchars[sigval >> 4];
    646 	  remcomOutBuffer[2] = hexchars[sigval & 0xf];
    647 	  remcomOutBuffer[3] = 0;
    648 	  break;
    649 
    650 	case 'd':		/* toggle debug flag */
    651 	  break;
    652 
    653 	case 'g':		/* return the value of the CPU registers */
    654 	  {
    655 	    ptr = remcomOutBuffer;
    656 	    ptr = mem2hex((char *)registers, ptr, 16 * 4, 0); /* G & O regs */
    657 	    ptr = mem2hex(sp + 0, ptr, 16 * 4, 0); /* L & I regs */
    658 	    memset(ptr, '0', 32 * 8); /* Floating point */
    659 	    mem2hex((char *)&registers[Y],
    660 		    ptr + 32 * 4 * 2,
    661 		    8 * 4,
    662 		    0);		/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
    663 	  }
    664 	  break;
    665 
    666 	case 'G':	   /* set the value of the CPU registers - return OK */
    667 	  {
    668 	    unsigned long *newsp, psr;
    669 
    670 	    psr = registers[PSR];
    671 
    672 	    hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
    673 	    hex2mem(ptr + 16 * 4 * 2, sp + 0, 16 * 4, 0); /* L & I regs */
    674 	    hex2mem(ptr + 64 * 4 * 2, (char *)&registers[Y],
    675 		    8 * 4, 0);	/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
    676 
    677 	    /* See if the stack pointer has moved.  If so, then copy the saved
    678 	       locals and ins to the new location.  This keeps the window
    679 	       overflow and underflow routines happy.  */
    680 
    681 	    newsp = (unsigned long *)registers[SP];
    682 	    if (sp != newsp)
    683 	      sp = memcpy(newsp, sp, 16 * 4);
    684 
    685 	    /* Don't allow CWP to be modified. */
    686 
    687 	    if (psr != registers[PSR])
    688 	      registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
    689 
    690 	    strcpy(remcomOutBuffer,"OK");
    691 	  }
    692 	  break;
    693 
    694 	case 'm':	  /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
    695 	  /* Try to read %x,%x.  */
    696 
    697 	  if (hexToInt(&ptr, &addr)
    698 	      && *ptr++ == ','
    699 	      && hexToInt(&ptr, &length))
    700 	    {
    701 	      if (mem2hex((char *)addr, remcomOutBuffer, length, 1))
    702 		break;
    703 
    704 	      strcpy (remcomOutBuffer, "E03");
    705 	    }
    706 	  else
    707 	    strcpy(remcomOutBuffer,"E01");
    708 	  break;
    709 
    710 	case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
    711 	  /* Try to read '%x,%x:'.  */
    712 
    713 	  if (hexToInt(&ptr, &addr)
    714 	      && *ptr++ == ','
    715 	      && hexToInt(&ptr, &length)
    716 	      && *ptr++ == ':')
    717 	    {
    718 	      if (hex2mem(ptr, (char *)addr, length, 1))
    719 		strcpy(remcomOutBuffer, "OK");
    720 	      else
    721 		strcpy(remcomOutBuffer, "E03");
    722 	    }
    723 	  else
    724 	    strcpy(remcomOutBuffer, "E02");
    725 	  break;
    726 
    727 	case 'c':    /* cAA..AA    Continue at address AA..AA(optional) */
    728 	  /* try to read optional parameter, pc unchanged if no parm */
    729 
    730 	  if (hexToInt(&ptr, &addr))
    731 	    {
    732 	      registers[PC] = addr;
    733 	      registers[NPC] = addr + 4;
    734 	    }
    735 
    736 /* Need to flush the instruction cache here, as we may have deposited a
    737    breakpoint, and the icache probably has no way of knowing that a data ref to
    738    some location may have changed something that is in the instruction cache.
    739  */
    740 
    741 	  flush_i_cache();
    742 	  return;
    743 
    744 	  /* kill the program */
    745 	case 'k' :		/* do nothing */
    746 	  break;
    747 #if 0
    748 	case 't':		/* Test feature */
    749 	  asm (" std %f30,[%sp]");
    750 	  break;
    751 #endif
    752 	case 'r':		/* Reset */
    753 	  asm ("call 0
    754 		nop ");
    755 	  break;
    756 	}			/* switch */
    757 
    758       /* reply to the request */
    759       putpacket(remcomOutBuffer);
    760     }
    761 }
    762 
    763 /* This function will generate a breakpoint exception.  It is used at the
    764    beginning of a program to sync up with a debugger and can be used
    765    otherwise as a quick means to stop program execution and "break" into
    766    the debugger. */
    767 
    768 void
    769 breakpoint (void)
    770 {
    771   if (!initialized)
    772     return;
    773 
    774   asm("	.globl _breakinst
    775 
    776 	_breakinst: ta 1
    777       ");
    778 }
    779