From 03261851a10dd2d6900a0a00a7515a0a46fb5d76 Mon Sep 17 00:00:00 2001 From: Ranjith Kumaran Date: Fri, 17 Mar 2000 22:48:54 +0000 Subject: 20000317 sourceware import --- libgloss/hp74x/pa_stub.c | 698 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 698 insertions(+) create mode 100644 libgloss/hp74x/pa_stub.c (limited to 'libgloss/hp74x/pa_stub.c') diff --git a/libgloss/hp74x/pa_stub.c b/libgloss/hp74x/pa_stub.c new file mode 100644 index 000000000..296492175 --- /dev/null +++ b/libgloss/hp74x/pa_stub.c @@ -0,0 +1,698 @@ +/* -*-C-*- +******************************************************************************* +* +* File: pa_stub.c +* RCS: $Header$ +* Description: main routines for PA RISC monitor stub +* Author: Robert Quist +* Created: Mon Nov 1 10:00:36 1993 +* Modified: Fri Nov 12 15:14:23 1993 (Robert Quist) quist@hpfcrdq +* Language: C +* Package: N/A +* Status: Experimental (Do Not Distribute) +* +******************************************************************************* +*/ + +/**************************************************************************** + + 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. + +****************************************************************************/ + +/**************************************************************************** + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * 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 + + + ************* + * + * 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) + * + * bBB..BB Set baud rate to BB..BB OK or BNN, then sets + * baud rate + * + + ************ + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of : + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * 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 +#include "hppa-defs.h" + +/************************************************************************ + * + * external low-level support + */ +#define OPT_PDC_CACHE 5 +#define OPT_PDC_ADD_VALID 12 +#define PGZ_MEM_PDC 0x0388 /* location of PDC_ENTRY in memory */ +#define CALL_PDC (*(int (*)())((int *)(*((int *)PGZ_MEM_PDC)))) + +extern putDebugChar(); /* write a single character */ +extern getDebugChar(); /* read and return a single char */ +extern FICE(); /* flush i cache entry */ +extern INLINE_BREAK(); /* break for user call */ + +#define RADDR_ALIGN(s,r) (s = ((unsigned int *) ((((int) r ) + 7 ) & 0xFFFFFFF8))) + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ + +#define BUFMAX 2048 + +#define NUMGPRS 32 +#define NUMSRS 8 +#define NUMCRS 32 +#define NUMSPCLS 3 +#define NUMFPRS 32 + +#define NUMGPRBYTES 4 +#define NUMSRBYTES 4 +#define NUMCRBYTES 4 +#define NUMSPCLBYTES 4 +#define NUMFPRBYTES 8 + +/* Number of bytes of registers. */ +#define NUMREGBYTES \ + ( (NUMGPRS * NUMGPRBYTES) \ + + (NUMSRS * NUMSRBYTES) \ + + (NUMCRS * NUMCRBYTES) \ + + (NUMSPCLS * NUMSPCLBYTES) \ + + (NUMFPRS * NUMFPRBYTES) \ + ) + + +enum regnames {GR0, GR1, GR2, GR3, GR4, GR5, GR6, GR7, + GR8, GR9, GR10, GR11, GR12, GR13, GR14, GR15, + GR16, GR17, GR18, GR19, GR20, GR21, GR22, GR23, + GR24, GR25, GR26, GR27, GR28, GR29, GR30, GR31, + + SR0, SR1, SR2, SR3, SR4, SR5, SR6, SR7, + + CR0, CR1, CR2, CR3, CR4, CR5, CR6, CR7, + CR8, CR9, CR10, CR11, CR12, CR13, CR14, CR15, + CR16, CR17H,CR18H,CR19, CR20, CR21, CR22, CR23, + CR24, CR25, CR26, CR27, CR28, CR29, CR30, CR31, + + CR17T,CR18T,CPUD0 }; + +enum fregnames {FPR0, FPR1, FPR2, FPR3, FPR4, FPR5, FPR6, FPR7, + FPR8, FPR9, FPR10, FPR11, FPR12, FPR13, FPR14, FPR15, + FPR16, FPR17, FPR18, FPR19, FPR20, FPR21, FPR22, FPR23, + FPR24, FPR25, FPR26, FPR27, FPR28, FPR29, FPR30, FPR31 }; + +#define PC CR18H +#define NPC CR18T +#define SP GR30 + +struct registers { + int intregs[NUMGPRS + NUMSRS + NUMCRS + NUMSPCLS]; + int fpregs [NUMFPRS * 2]; + }; +/* Global Variables */ + +static int initialized = 0; /* !0 means we've been initialized */ +static unsigned char hexchars[]="0123456789abcdef"; +static unsigned char remcomInBuffer[BUFMAX]; +static unsigned char remcomOutBuffer[BUFMAX]; +static unsigned int i_cache_params[6]; + +/* This table contains the mapping between PA hardware exception + types, and signals, which are primarily what GDB understands. It also + indicates which hardware traps we need to commandeer when initializing + the stub. + + The only two currently used are Recovery counter (single stepping) + and Break trap ( break points ). +*/ + +static struct hard_trap_info +{ + unsigned char tt; /* Trap number for PA-RISC */ + unsigned char signo; /* Signal that we map this trap into */ +} hard_trap_info[] = { +/* 1 High priority machine check */ +/* 2 Power failure interrupt*/ +/* 3 Recovery counter -- init */ +/* 4 External interrupt */ +/* 5 Low priority machine check */ + {6, SIGSEGV}, /* Instruction TLB miss/page fault */ + {7, SIGSEGV}, /* Memory protection */ + {8, SIGILL}, /* Illegal instruction */ + {9, SIGTRAP}, /* Break instruction -- init */ + {10,SIGILL}, /* Privileged instruction */ + {11,SIGILL}, /* Privileged register */ + {12,SIGUSR1}, /* Overflow */ + {13,SIGUSR2}, /* Conditional */ + {14,SIGEMT}, /* Assist Exception */ + {15,SIGSEGV}, /* Data TLB miss/page fault */ + {16,SIGSEGV}, /* Non-access Instruction TLB miss */ + {17,SIGSEGV}, /* Non-access Data TLB miss/page fault */ + {18,SIGSEGV}, /* Data memory protection/ unaligned data reference */ + {19,SIGTRAP}, /* Data memory break */ + {20,SIGSEGV}, /* TLB dirty bit */ + {21,SIGSEGV}, /* Page reference */ + {22,SIGEMT}, /* Assist emulation */ + {23,SIGILL}, /* Higher-privilege */ + {24,SIGILL}, /* Lower-privilege */ + {25,SIGTRAP}, /* Taken branch */ + {0, 0} /* Must be last */ +}; + +/* Functions */ +/*========================================================================== */ + +/* Convert ch from a hex digit to an int */ + +static int +hex(ch) + unsigned 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 $# */ + +static void +getpacket(buffer) + char *buffer; +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + unsigned char ch; + + do + { + /* wait around for the start character, ignore all other characters */ + strobe(); + 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; + } + + if (count >= BUFMAX) + continue; + + buffer[count] = 0; + + if (ch == '#') + { + xmitcsum = hex(getDebugChar()) << 4; + xmitcsum |= hex(getDebugChar()); + +#if TESTING + /* Humans shouldn't have to figure out checksums to type to it. */ + putDebugChar ('+'); + return; +#endif + 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. */ + +static void +putpacket(buffer) + unsigned char *buffer; +{ + unsigned char checksum; + int count; + unsigned char ch; + + /* $#. */ + + 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 & 0xf]); + } while (getDebugChar() != '+'); +} + +/* Convert the memory pointed to by mem into hex, placing result in buf. + * Return a pointer to the last char put in buf (null), in case of mem fault, + * return 0. + * If MAY_FAULT is non-zero, then we will handle memory faults by returning + * a 0, else treat a fault like any other fault in the stub. + */ + +static unsigned char * +mem2hex(mem, buf, count, may_fault) + unsigned char *mem; + unsigned char *buf; + int count; + int may_fault; +{ + unsigned char ch; + int check_addr, + new_addr; + + check_addr = 0; + + while (count-- > 0) + { + if (may_fault) + { new_addr = ((int) (mem+3)) & 0xFFFFFFF8; + if (new_addr != check_addr) + { check_addr = new_addr; + if (pdc_call(OPT_PDC_ADD_VALID,0,check_addr)) return 0; + } + } + ch = *mem++; + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch & 0xf]; + } + + *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 */ + +static unsigned char * +hex2mem(buf, mem, count, may_fault) + unsigned char *buf; + unsigned char *mem; + int count; + int may_fault; +{ + int i; + unsigned int ch; + int check_addr, + new_addr; + + check_addr = 0; + + for (i=0; itt && ht->signo; ht++) + if (ht->tt == tt) + return ht->signo; + + return SIGHUP; /* default for things we don't know about */ +} + +/* + * While we find nice hex chars, build an int. + * Return number of chars processed. + */ + +static int +hexToInt(ptr, intValue) + unsigned char **ptr; + int *intValue; +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) + { + hexValue = hex(**ptr); + if (hexValue < 0) + break; + + *intValue = (*intValue << 4) | hexValue; + numChars ++; + + (*ptr)++; + } + + return (numChars); +} + +void +flush_i_cache() + +{ + unsigned int addr,count,loop; + + if (i_cache_params[0] <= 0) return; + + addr = i_cache_params[2]; + for (count = 0; count < i_cache_params[4]; count++) + { for ( loop = 0; loop < i_cache_params[5]; loop++) FICE(addr); + addr = addr + i_cache_params[3]; + } +} + +/* + * This function does all command procesing for interfacing to gdb. + return of 0 will execute DEBUG_GO (continue) + return of 1 will execute DEBUG_SS (single step) + */ + +int +handle_exception (registers,tt) + unsigned long *registers; + int tt; /* Trap type */ +{ + int sigval; + int addr; + int length; + unsigned char *ptr; + + /* reply to host that an exception has occurred */ + sigval = computeSignal(tt); + ptr = remcomOutBuffer; + + *ptr++ = 'T'; + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + +/* could be lots of stuff here like PC and SP registers */ + + *ptr++ = 0; + + putpacket(remcomOutBuffer); + + while (1) + { + remcomOutBuffer[0] = 0; + + getpacket(remcomInBuffer); + switch (remcomInBuffer[0]) + { + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval & 0xf]; + remcomOutBuffer[3] = 0; + break; + + case 'd': + /* toggle debug flag */ + led_putnum (16); + break; + + case 'g': /* return the value of the CPU registers */ + { + ptr = remcomOutBuffer; + /* GR0..GR31 SR0..SR7 CR0..CR31 specials */ + ptr = mem2hex((char *)registers, ptr, NUMREGBYTES, 0); + /* need to add floating point registers */ + } + break; + + case 'G': /* set the value of the CPU registers - return OK */ + { + ptr = &remcomInBuffer[1]; + /* GR0..GR31 SR0..SR7 CR0..CR31 specials */ + hex2mem(ptr, (char *)registers, NUMREGBYTES, 0); + strcpy(remcomOutBuffer,"OK 1"); + } + break; + + case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + /* Try to read %x,%x. */ + + ptr = &remcomInBuffer[1]; + + if (hexToInt(&ptr, &addr) + && *ptr++ == ',' + && hexToInt(&ptr, &length)) + { + if (mem2hex((char *)addr, remcomOutBuffer, length, 1)) + break; + + strcpy (remcomOutBuffer, "E03"); + } + else + strcpy(remcomOutBuffer,"E01"); + break; + + case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + /* Try to read '%x,%x:'. */ + + ptr = &remcomInBuffer[1]; + + if (hexToInt(&ptr, &addr) + && *ptr++ == ',' + && hexToInt(&ptr, &length) + && *ptr++ == ':') + { + if (hex2mem(ptr, (char *)addr, length, 1)) + strcpy(remcomOutBuffer, "OK"); + else + strcpy(remcomOutBuffer, "E03"); + } + else + strcpy(remcomOutBuffer, "E02"); + break; + + case 'c': /* cAA..AA Continue at address AA..AA(optional) */ + /* try to read optional parameter, pc unchanged if no parm */ + + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr)) + { + registers[PC] = addr; + registers[NPC] = addr + 4; + } + +/* Need to flush the instruction cache here, as we may have deposited a + breakpoint, and the icache probably has no way of knowing that a data ref to + some location may have changed something that is in the instruction cache. + */ + + flush_i_cache(); + return 0; /* execute GO */ + + /* kill the program */ + case 'k' : /* do nothing */ + break; + + case 's' : /* single step */ + /* try to read optional parameter, pc unchanged if no parm */ + + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr, &addr)) + { + registers[PC] = addr; + registers[NPC] = addr + 4; + } +/* Need to flush the instruction cache here, as we may have deposited a + breakpoint, and the icache probably has no way of knowing that a data ref to + some location may have changed something that is in the instruction cache. + */ + flush_i_cache(); + return 1; /* execute Single Step */ + break; + +#if TESTING1 + case 't': /* Test feature */ + break; +#endif + case 'r': /* Reset */ + break; + +#if TESTING2 +Disabled until we can unscrew this properly + + case 'b': /* bBB... Set baud rate to BB... */ + { + int baudrate; + extern void set_timer_3(); + + ptr = &remcomInBuffer[1]; + if (!hexToInt(&ptr, &baudrate)) + { + strcpy(remcomOutBuffer,"B01"); + break; + } + + /* Convert baud rate to uart clock divider */ + switch (baudrate) + { + case 38400: + baudrate = 16; + break; + case 19200: + baudrate = 33; + break; + case 9600: + baudrate = 65; + break; + default: + strcpy(remcomOutBuffer,"B02"); + goto x1; + } + + putpacket("OK 2"); /* Ack before changing speed */ + set_timer_3(baudrate); /* Set it */ + } +x1: break; +#endif + } /* switch */ + + /* reply to the request */ + putpacket(remcomOutBuffer); + } + print ("\r\nEscaped handle_exception\r\n"); +} -- cgit v1.2.3