diff options
author | Ranjith Kumaran <ranjith@cygnus.com> | 2000-03-17 22:48:54 +0000 |
---|---|---|
committer | Ranjith Kumaran <ranjith@cygnus.com> | 2000-03-17 22:48:54 +0000 |
commit | 03261851a10dd2d6900a0a00a7515a0a46fb5d76 (patch) | |
tree | 7c22ac6cbbc99fd5cd1b5426853be8d4fd7bfcf1 /libgloss/m68k/mvme-stub.c | |
parent | fae4c299f14fc23e2829c8656992eba21f79242a (diff) | |
download | cygnal-03261851a10dd2d6900a0a00a7515a0a46fb5d76.tar.gz cygnal-03261851a10dd2d6900a0a00a7515a0a46fb5d76.tar.bz2 cygnal-03261851a10dd2d6900a0a00a7515a0a46fb5d76.zip |
20000317 sourceware import
Diffstat (limited to 'libgloss/m68k/mvme-stub.c')
-rw-r--r-- | libgloss/m68k/mvme-stub.c | 734 |
1 files changed, 734 insertions, 0 deletions
diff --git a/libgloss/m68k/mvme-stub.c b/libgloss/m68k/mvme-stub.c new file mode 100644 index 000000000..fbc4c61b5 --- /dev/null +++ b/libgloss/m68k/mvme-stub.c @@ -0,0 +1,734 @@ +unsigned long sp_ptr; +unsigned long pc_ptr; +int cnt; +#define UNWIND asm ("movel %/sp, %0" : "=g" (sp_ptr));\ + printf ("\n\t\t== Starting at 0x%x ==\n", sp_ptr);\ + for (cnt=4; cnt <=32; cnt+=4) {\ + printf ("+%d(0x%x): 0x%x\t\t-%d(0x%x): 0x%x\n",\ + cnt, (sp_ptr + cnt), *(unsigned long *)(sp_ptr + cnt),\ + cnt, (sp_ptr - cnt), *(unsigned long *)(sp_ptr - cnt)\ + ); }; fflush (stdout); + +/**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or it's performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing a trap #1. + * + * Some explanation is probably necessary to explain how exceptions are + * handled. When an exception is encountered the 68000 pushes the current + * program counter and status register onto the supervisor stack and then + * transfers execution to a location specified in it's vector table. + * The handlers for the exception vectors are hardwired to jmp to an address + * given by the relation: (exception - 256) * 6. These are decending + * addresses starting from -6, -12, -18, ... By allowing 6 bytes for + * each entry, a jsr, jmp, bsr, ... can be used to enter the exception + * handler. Using a jsr to handle an exception has an added benefit of + * allowing a single handler to service several exceptions and use the + * return address as the key differentiation. The vector number can be + * computed from the return address by [ exception = (addr + 1530) / 6 ]. + * The sole purpose of the routine _catchException is to compute the + * exception number and push it on the stack in place of the return address. + * The external function exceptionHandler() is + * used to attach a specific handler to a specific 68k exception. + * For 68020 machines, the ability to have a return address around just + * so the vector can be determined is not necessary because the '020 pushes an + * extra word onto the stack containing the vector offset + * + * Because gdb will sometimes write to the stack area to execute function + * calls, this program cannot rely on using the supervisor stack so it + * uses it's own stack area reserved in the int array remcomStack. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $<packet info>#<checksum>. + * + * where + * <packet info> :: <characters representing the command or response> + * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>> + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <setjmp.h> +#include <_ansi.h> + +/************************************************************************ + * + * external low-level support routines + */ +typedef void (*ExceptionHook)(int); /* pointer to function with int parm */ +typedef void (*Function)(); /* pointer to a function */ + +extern int putDebugChar(); /* write a single character */ +extern char getDebugChar(); /* read and return a single char */ + +ExceptionHook exceptionHook; /* hook variable for errors/exceptions */ + +/************************/ +/* FORWARD DECLARATIONS */ +/************************/ +/** static void initializeRemcomErrorFrame PARAMS ((void)); **/ +static void _DEFUN_VOID (initializeRemcomErrorFrame); + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +#define BUFMAX 400 + +static char initialized; /* boolean flag. != 0 means we've been initialized */ + +int remote_debug = 0; /*** Robs Thu Sep 24 22:18:51 PDT 1992 ***/ +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ + +static const char hexchars[]="0123456789abcdef"; + +/* there are 180 bytes of registers on a 68020 w/68881 */ +/* many of the fpa registers are 12 byte (96 bit) registers */ +#define NUMREGBYTES 180 +enum regnames {D0,D1,D2,D3,D4,D5,D6,D7, + A0,A1,A2,A3,A4,A5,A6,A7, + PS,PC, + FP0,FP1,FP2,FP3,FP4,FP5,FP6,FP7, + FPCONTROL,FPSTATUS,FPIADDR + }; + +typedef struct FrameStruct +{ + struct FrameStruct *previous; + int exceptionPC; /* pc value when this frame created */ + int exceptionVector; /* cpu vector causing exception */ + short frameSize; /* size of cpu frame in words */ + short sr; /* for 68000, this not always sr */ + int pc; + short format; + int fsaveHeader; + int morejunk[0]; /* exception frame, fp save... */ +} Frame; + +#define FRAMESIZE 500 +int gdbFrameStack[FRAMESIZE]; +Frame *lastFrame; + +/* + * these should not be static cuz they can be used outside this module + */ +int registers[NUMREGBYTES/4]; +int superStack; + +#define STACKSIZE 10000 +int remcomStack[STACKSIZE/sizeof(int)]; +int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1]; + +/* + * In many cases, the system will want to continue exception processing + * when a continue command is given. + * oldExceptionHook is a function to invoke in this case. + */ + +static ExceptionHook oldExceptionHook; + +/* the size of the exception stack on the 68020 varies with the type of + * exception. The following table is the number of WORDS used + * for each exception format. + */ +const short exceptionSize[] = { 4,4,6,4,4,4,4,4,29,10,16,46,12,4,4,4 }; + +/************* jump buffer used for setjmp/longjmp **************************/ +jmp_buf remcomEnv; + +#define BREAKPOINT() asm(" trap #1"); + +extern void _DEFUN_VOID (return_to_super); +extern void _DEFUN_VOID (return_to_user); +extern void _DEFUN_VOID (_catchException); + +void _returnFromException( Frame *frame ) +{ + /* if no passed in frame, use the last one */ + if (! frame) + { + frame = lastFrame; + frame->frameSize = 4; + frame->format = 0; + frame->fsaveHeader = -1; /* restore regs, but we dont have fsave info*/ + } + +#ifndef mc68020 + /* a 68000 cannot use the internal info pushed onto a bus error + * or address error frame when doing an RTE so don't put this info + * onto the stack or the stack will creep every time this happens. + */ + frame->frameSize=3; +#endif + + /* throw away any frames in the list after this frame */ + lastFrame = frame; + + frame->sr = registers[(int) PS]; + frame->pc = registers[(int) PC]; + + if (registers[(int) PS] & 0x2000) + { + /* return to supervisor mode... */ + return_to_super(); + } + else + { /* return to user mode */ + return_to_user(); + } +} + +int hex(ch) +char ch; +{ + if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10); + if ((ch >= '0') && (ch <= '9')) return (ch-'0'); + if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10); + return (-1); +} + + +/* scan for the sequence $<data>#<checksum> */ +void getpacket(buffer) +char * buffer; +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + char ch; + + if (remote_debug) { + printf("\nGETPACKET: sr=0x%x, pc=0x%x, sp=0x%x\n", + registers[ PS ], + registers[ PC ], + registers[ A7 ] + ); fflush (stdout); + UNWIND + } + + do { + /* wait around for the start character, ignore all other characters */ + while ((ch = getDebugChar()) != '$'); + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) { + ch = getDebugChar(); + if (ch == '#') break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(getDebugChar()) << 4; + xmitcsum += hex(getDebugChar()); + if ((remote_debug ) && (checksum != xmitcsum)) { + fprintf(stderr,"bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", + checksum,xmitcsum,buffer); + } + + if (checksum != xmitcsum) putDebugChar('-'); /* failed checksum */ + else { + putDebugChar('+'); /* successful transfer */ + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') { + putDebugChar( buffer[0] ); + putDebugChar( buffer[1] ); + /* remove sequence chars from buffer */ + count = strlen(buffer); + for (i=3; i <= count; i++) buffer[i-3] = buffer[i]; + } + } + } + } while (checksum != xmitcsum); + +} + +/* send the packet in buffer. The host get's one chance to read it. + This routine does not wait for a positive acknowledge. */ + +void putpacket(buffer) +char * buffer; +{ + unsigned char checksum; + int count; + char ch; + + /* $<packet info>#<checksum>. */ + /*** do {***/ + putDebugChar('$'); + checksum = 0; + count = 0; + + while (ch=buffer[count]) { + if (! putDebugChar(ch)) return; + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + + if (remote_debug) { + printf("\nPUTPACKET: sr=0x%x, pc=0x%x, sp=0x%x\n", + registers[ PS ], + registers[ PC ], + registers[ A7 ] + ); fflush (stdout); + UNWIND + } + +/*** } while (getDebugChar() != '+'); ***/ +/** } while (1 == 0); (getDebugChar() != '+'); **/ + +} + +char remcomInBuffer[BUFMAX]; +char remcomOutBuffer[BUFMAX]; +static short error; + + +void debug_error(format, parm) +char * format; +char * parm; +{ + if (remote_debug) fprintf(stderr,format,parm); +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +char* mem2hex(mem, buf, count) +char* mem; +char* buf; +int count; +{ + int i; + unsigned char ch; + for (i=0;i<count;i++) { + ch = *mem++; + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + return(buf); +} + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return a pointer to the character AFTER the last byte written */ +char* hex2mem(buf, mem, count) +char* buf; +char* mem; +int count; +{ + int i; + unsigned char ch; + for (i=0;i<count;i++) { + ch = hex(*buf++) << 4; + ch = ch + hex(*buf++); + *mem++ = ch; + } + return(mem); +} + +/* a bus error has occurred, perform a longjmp + to return execution and allow handling of the error */ + +void handle_buserror() +{ + longjmp(remcomEnv,1); +} + +/* this function takes the 68000 exception number and attempts to + translate this number into a unix compatible signal value */ +int computeSignal( exceptionVector ) +int exceptionVector; +{ + int sigval; + switch (exceptionVector) { + case 2 : sigval = 10; break; /* bus error */ + case 3 : sigval = 10; break; /* address error */ + case 4 : sigval = 4; break; /* illegal instruction */ + case 5 : sigval = 8; break; /* zero divide */ + case 6 : sigval = 16; break; /* chk instruction */ + case 7 : sigval = 16; break; /* trapv instruction */ + case 8 : sigval = 11; break; /* privilege violation */ + case 9 : sigval = 5; break; /* trace trap */ + case 10: sigval = 4; break; /* line 1010 emulator */ + case 11: sigval = 4; break; /* line 1111 emulator */ + case 13: sigval = 8; break; /* floating point err */ + case 31: sigval = 2; break; /* interrupt */ + case 33: sigval = 5; break; /* breakpoint */ + case 40: sigval = 8; break; /* floating point err */ + case 48: sigval = 8; break; /* floating point err */ + case 49: sigval = 8; break; /* floating point err */ + case 50: sigval = 8; break; /* zero divide */ + case 51: sigval = 8; break; /* underflow */ + case 52: sigval = 8; break; /* operand error */ + case 53: sigval = 8; break; /* overflow */ + case 54: sigval = 8; break; /* NAN */ + default: + sigval = 7; /* "software generated"*/ + } + return (sigval); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +int hexToInt(char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) + { + hexValue = hex(**ptr); + if (hexValue >=0) + { + *intValue = (*intValue <<4) | hexValue; + numChars ++; + } + else + break; + + (*ptr)++; + } + + return (numChars); +} + +/* + * This function does all command procesing for interfacing to gdb. + */ +void handle_exception(int exceptionVector) +{ + int sigval; + int addr, length; + char * ptr; + int newPC; + Frame *frame; + + if (remote_debug) printf("\nHANDLE_EXCEPTION: vector=%d, sr=0x%x, pc=0x%x, sp=0x%x\n", + exceptionVector, + registers[ PS ], + registers[ PC ], + registers[ A7 ] + ); fflush (stdout); + + /* reply to host that an exception has occurred */ + sigval = computeSignal( exceptionVector ); + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + + putpacket(remcomOutBuffer); + + while (1==1) { + error = 0; + remcomOutBuffer[0] = 0; + getpacket(remcomInBuffer); + switch (remcomInBuffer[0]) { + case '?' : remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd' : remote_debug = !(remote_debug); /* toggle debug flag */ + break; + case 'g' : /* return the value of the CPU registers */ + mem2hex((char*) registers, remcomOutBuffer, NUMREGBYTES); + break; + case 'G' : /* set the value of the CPU registers - return OK */ + hex2mem(&remcomInBuffer[1], (char*) registers, NUMREGBYTES); + strcpy(remcomOutBuffer,"OK"); + break; + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm' : + if (setjmp(remcomEnv) == 0) + { + exceptionHandler(2,handle_buserror); + + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr,&addr)) + if (*(ptr++) == ',') + if (hexToInt(&ptr,&length)) + { + ptr = 0; + mem2hex((char*) addr, remcomOutBuffer, length); + } + + if (ptr) + { + strcpy(remcomOutBuffer,"E01"); + debug_error("malformed read memory command: %s",remcomInBuffer); + } + } + else { + exceptionHandler(2,_catchException); + strcpy(remcomOutBuffer,"E03"); + debug_error("bus error"); + } + + /* restore handler for bus error */ + exceptionHandler(2,_catchException); + break; + + /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + case 'M' : + if (setjmp(remcomEnv) == 0) { + exceptionHandler(2,handle_buserror); + + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr,&addr)) + if (*(ptr++) == ',') + if (hexToInt(&ptr,&length)) + if (*(ptr++) == ':') + { + hex2mem(ptr, (char*) addr, length); + ptr = 0; + strcpy(remcomOutBuffer,"OK"); + } + if (ptr) + { + strcpy(remcomOutBuffer,"E02"); + debug_error("malformed write memory command: %s",remcomInBuffer); + } + } + else { + exceptionHandler(2,_catchException); + strcpy(remcomOutBuffer,"E03"); + debug_error("bus error"); + } + + /* restore handler for bus error */ + exceptionHandler(2,_catchException); + break; + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + case 'c' : + case 's' : + /* try to read optional parameter, pc unchanged if no parm */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr,&addr)) + registers[ PC ] = addr; + + newPC = registers[ PC]; + + /* clear the trace bit */ + registers[ PS ] &= 0x7fff; + + /* set the trace bit if we're stepping */ + if (remcomInBuffer[0] == 's') registers[ PS ] |= 0x8000; + + /* + * look for newPC in the linked list of exception frames. + * if it is found, use the old frame it. otherwise, + * fake up a dummy frame in returnFromException(). + */ + if (remote_debug) printf("new pc = 0x%x\n",newPC); + frame = lastFrame; + while (frame) + { + if (remote_debug) + printf("frame at 0x%x has pc=0x%x, except#=%d\n", + frame,frame->exceptionPC, + frame->exceptionVector); + if (frame->exceptionPC == newPC) break; /* bingo! a match */ + /* + * for a breakpoint instruction, the saved pc may + * be off by two due to re-executing the instruction + * replaced by the trap instruction. Check for this. + */ + if ((frame->exceptionVector == 33) && + (frame->exceptionPC == (newPC+2))) break; + if (frame == frame->previous) + { + frame = 0; /* no match found */ + break; + } + frame = frame->previous; + } + + /* + * If we found a match for the PC AND we are not returning + * as a result of a breakpoint (33), + * trace exception (9), nmi (31), jmp to + * the old exception handler as if this code never ran. + */ + if (frame) + { + if ((frame->exceptionVector != 9) && + (frame->exceptionVector != 31) && + (frame->exceptionVector != 33)) + { + /* + * invoke the previous handler. + */ + if (oldExceptionHook) + (*oldExceptionHook) (frame->exceptionVector); + newPC = registers[ PC ]; /* pc may have changed */ + if (newPC != frame->exceptionPC) + { + if (remote_debug) + printf("frame at 0x%x has pc=0x%x, except#=%d\n", + frame,frame->exceptionPC, + frame->exceptionVector); + /* re-use the last frame, we're skipping it (longjump?)*/ + frame = (Frame *) 0; + _returnFromException( frame ); /* this is a jump */ + } + } + } + + /* if we couldn't find a frame, create one */ + if (frame == 0) + { + frame = lastFrame -1 ; + + /* by using a bunch of print commands with breakpoints, + it's possible for the frame stack to creep down. If it creeps + too far, give up and reset it to the top. Normal use should + not see this happen. + */ + if ((unsigned int) (frame-2) < (unsigned int) &gdbFrameStack) + { + initializeRemcomErrorFrame(); + frame = lastFrame; + } + frame->previous = lastFrame; + lastFrame = frame; + frame = 0; /* null so _return... will properly initialize it */ + } + + _returnFromException( frame ); /* this is a jump */ + + break; + + /* kill the program */ + case 'k' : /* do nothing */ + break; + } /* switch */ + + /* reply to the request */ + putpacket(remcomOutBuffer); + } +} + + +void initializeRemcomErrorFrame() +{ + lastFrame = ((Frame *) &gdbFrameStack[FRAMESIZE-1]) - 1; + lastFrame->previous = lastFrame; +} + +/* this function is used to set up exception handlers for tracing and + breakpoints */ +void set_debug_traps() +{ +extern void _debug_level7(); +extern void remcomHandler(); +int exception; + + initializeRemcomErrorFrame(); + stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1]; + + setup_vectors(); + + if (oldExceptionHook != remcomHandler) + { + oldExceptionHook = exceptionHook; + exceptionHook = remcomHandler; + } + + initialized = 1; + +} +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void breakpoint() +{ + if (initialized) BREAKPOINT(); +} |