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