|  | /* sh-stub.c -- debugging stub for the Renesas-SH. | 
|  |  | 
|  | NOTE!! This code has to be compiled with optimization, otherwise the | 
|  | function inlining which generates the exception handlers won't work. | 
|  |  | 
|  | */ | 
|  |  | 
|  | /*   This is originally based on an m68k software stub written by Glenn | 
|  | Engel at HP, but has changed quite a bit. | 
|  |  | 
|  | Modifications for the SH by Ben Lee and Steve Chamberlain | 
|  |  | 
|  | */ | 
|  |  | 
|  | /**************************************************************************** | 
|  |  | 
|  | 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. | 
|  |  | 
|  | ****************************************************************************/ | 
|  |  | 
|  |  | 
|  | /* Remote communication protocol. | 
|  |  | 
|  | A debug packet whose contents are <data> | 
|  | is encapsulated for transmission in the form: | 
|  |  | 
|  | $ <data> # CSUM1 CSUM2 | 
|  |  | 
|  | <data> must be ASCII alphanumeric and cannot include characters | 
|  | '$' or '#'.  If <data> starts with two characters followed by | 
|  | ':', then the existing stubs interpret this as a sequence number. | 
|  |  | 
|  | CSUM1 and CSUM2 are ascii hex representation of an 8-bit | 
|  | checksum of <data>, the most significant nibble is sent first. | 
|  | the hex digits 0-9,a-f are used. | 
|  |  | 
|  | Receiver responds with: | 
|  |  | 
|  | +	- if CSUM is correct and ready for next packet | 
|  | -	- if CSUM is incorrect | 
|  |  | 
|  | <data> is as follows: | 
|  | All values are encoded in ascii hex digits. | 
|  |  | 
|  | Request		Packet | 
|  |  | 
|  | read registers  g | 
|  | reply		XX....X		Each byte of register data | 
|  | is described by two hex digits. | 
|  | Registers are in the internal order | 
|  | for GDB, and the bytes in a register | 
|  | are in the same order the machine uses. | 
|  | or ENN		for an error. | 
|  |  | 
|  | write regs	GXX..XX		Each byte of register data | 
|  | is described by two hex digits. | 
|  | reply		OK		for success | 
|  | ENN		for an error | 
|  |  | 
|  | write reg	Pn...=r...	Write register n... with value r..., | 
|  | which contains two hex digits for each | 
|  | byte in the register (target byte | 
|  | order). | 
|  | reply		OK		for success | 
|  | ENN		for an error | 
|  | (not supported by all stubs). | 
|  |  | 
|  | read mem	mAA..AA,LLLL	AA..AA is address, LLLL is length. | 
|  | reply		XX..XX		XX..XX is mem contents | 
|  | Can be fewer bytes than requested | 
|  | if able to read only part of the data. | 
|  | or ENN		NN is errno | 
|  |  | 
|  | write mem	MAA..AA,LLLL:XX..XX | 
|  | AA..AA is address, | 
|  | LLLL is number of bytes, | 
|  | XX..XX is data | 
|  | reply		OK		for success | 
|  | ENN		for an error (this includes the case | 
|  | where only part of the data was | 
|  | written). | 
|  |  | 
|  | cont		cAA..AA		AA..AA is address to resume | 
|  | If AA..AA is omitted, | 
|  | resume at same address. | 
|  |  | 
|  | step		sAA..AA		AA..AA is address to resume | 
|  | If AA..AA is omitted, | 
|  | resume at same address. | 
|  |  | 
|  | last signal     ?               Reply the current reason for stopping. | 
|  | This is the same reply as is generated | 
|  | for step or cont : SAA where AA is the | 
|  | signal number. | 
|  |  | 
|  | There is no immediate reply to step or cont. | 
|  | The reply comes when the machine stops. | 
|  | It is		SAA		AA is the "signal number" | 
|  |  | 
|  | or...		TAAn...:r...;n:r...;n...:r...; | 
|  | AA = signal number | 
|  | n... = register number | 
|  | r... = register contents | 
|  | or...		WAA		The process exited, and AA is | 
|  | the exit status.  This is only | 
|  | applicable for certain sorts of | 
|  | targets. | 
|  | kill request	k | 
|  |  | 
|  | toggle debug	d		toggle debug flag (see 386 & 68k stubs) | 
|  | reset		r		reset -- see sparc stub. | 
|  | reserved	<other>		On other requests, the stub should | 
|  | ignore the request and send an empty | 
|  | response ($#<checksum>).  This way | 
|  | we can extend the protocol and GDB | 
|  | can tell whether the stub it is | 
|  | talking to uses the old or the new. | 
|  | search		tAA:PP,MM	Search backwards starting at address | 
|  | AA for a match with pattern PP and | 
|  | mask MM.  PP and MM are 4 bytes. | 
|  | Not supported by all stubs. | 
|  |  | 
|  | general query	qXXXX		Request info about XXXX. | 
|  | general set	QXXXX=yyyy	Set value of XXXX to yyyy. | 
|  | query sect offs	qOffsets	Get section offsets.  Reply is | 
|  | Text=xxx;Data=yyy;Bss=zzz | 
|  | console output	Otext		Send text to stdout.  Only comes from | 
|  | remote target. | 
|  |  | 
|  | Responses can be run-length encoded to save space.  A '*' means that | 
|  | the next character is an ASCII encoding giving a repeat count which | 
|  | stands for that many repetitions of the character preceding the '*'. | 
|  | The encoding is n+29, yielding a printable character where n >=3 | 
|  | (which is where rle starts to win).  Don't use an n > 126. | 
|  |  | 
|  | So | 
|  | "0* " means the same as "0000".  */ | 
|  |  | 
|  | #include <string.h> | 
|  | #include <setjmp.h> | 
|  |  | 
|  | /* Renesas SH architecture instruction encoding masks */ | 
|  |  | 
|  | #define COND_BR_MASK   0xff00 | 
|  | #define UCOND_DBR_MASK 0xe000 | 
|  | #define UCOND_RBR_MASK 0xf0df | 
|  | #define TRAPA_MASK     0xff00 | 
|  |  | 
|  | #define COND_DISP      0x00ff | 
|  | #define UCOND_DISP     0x0fff | 
|  | #define UCOND_REG      0x0f00 | 
|  |  | 
|  | /* Renesas SH instruction opcodes */ | 
|  |  | 
|  | #define BF_INSTR       0x8b00 | 
|  | #define BT_INSTR       0x8900 | 
|  | #define BRA_INSTR      0xa000 | 
|  | #define BSR_INSTR      0xb000 | 
|  | #define JMP_INSTR      0x402b | 
|  | #define JSR_INSTR      0x400b | 
|  | #define RTS_INSTR      0x000b | 
|  | #define RTE_INSTR      0x002b | 
|  | #define TRAPA_INSTR    0xc300 | 
|  | #define SSTEP_INSTR    0xc3ff | 
|  |  | 
|  | /* Renesas SH processor register masks */ | 
|  |  | 
|  | #define T_BIT_MASK     0x0001 | 
|  |  | 
|  | /* | 
|  | * BUFMAX defines the maximum number of characters in inbound/outbound | 
|  | * buffers. At least NUMREGBYTES*2 are needed for register packets. | 
|  | */ | 
|  | #define BUFMAX 1024 | 
|  |  | 
|  | /* | 
|  | * Number of bytes for registers | 
|  | */ | 
|  | #define NUMREGBYTES 112		/* 92 */ | 
|  |  | 
|  | /* | 
|  | * typedef | 
|  | */ | 
|  | typedef void (*Function) (); | 
|  |  | 
|  | /* | 
|  | * Forward declarations | 
|  | */ | 
|  |  | 
|  | static int hex (char); | 
|  | static char *mem2hex (char *, char *, int); | 
|  | static char *hex2mem (char *, char *, int); | 
|  | static int hexToInt (char **, int *); | 
|  | static unsigned char *getpacket (void); | 
|  | static void putpacket (char *); | 
|  | static void handle_buserror (void); | 
|  | static int computeSignal (int exceptionVector); | 
|  | static void handle_exception (int exceptionVector); | 
|  | void init_serial(); | 
|  |  | 
|  | void putDebugChar (char); | 
|  | char getDebugChar (void); | 
|  |  | 
|  | /* These are in the file but in asm statements so the compiler can't see them */ | 
|  | void catch_exception_4 (void); | 
|  | void catch_exception_6 (void); | 
|  | void catch_exception_9 (void); | 
|  | void catch_exception_10 (void); | 
|  | void catch_exception_11 (void); | 
|  | void catch_exception_32 (void); | 
|  | void catch_exception_33 (void); | 
|  | void catch_exception_255 (void); | 
|  |  | 
|  |  | 
|  |  | 
|  | #define catch_exception_random catch_exception_255 /* Treat all odd ones like 255 */ | 
|  |  | 
|  | void breakpoint (void); | 
|  |  | 
|  |  | 
|  | #define init_stack_size 8*1024  /* if you change this you should also modify BINIT */ | 
|  | #define stub_stack_size 8*1024 | 
|  |  | 
|  | int init_stack[init_stack_size] __attribute__ ((section ("stack"))) = {0}; | 
|  | int stub_stack[stub_stack_size] __attribute__ ((section ("stack"))) = {0}; | 
|  |  | 
|  |  | 
|  | void INIT (); | 
|  | void BINIT (); | 
|  |  | 
|  | #define CPU_BUS_ERROR_VEC  9 | 
|  | #define DMA_BUS_ERROR_VEC 10 | 
|  | #define NMI_VEC           11 | 
|  | #define INVALID_INSN_VEC   4 | 
|  | #define INVALID_SLOT_VEC   6 | 
|  | #define TRAP_VEC          32 | 
|  | #define IO_VEC            33 | 
|  | #define USER_VEC         255 | 
|  |  | 
|  |  | 
|  |  | 
|  | char in_nmi;   /* Set when handling an NMI, so we don't reenter */ | 
|  | int dofault;  /* Non zero, bus errors will raise exception */ | 
|  |  | 
|  | int *stub_sp; | 
|  |  | 
|  | /* debug > 0 prints ill-formed commands in valid packets & checksum errors */ | 
|  | int remote_debug; | 
|  |  | 
|  | /* jump buffer used for setjmp/longjmp */ | 
|  | jmp_buf remcomEnv; | 
|  |  | 
|  | enum regnames | 
|  | { | 
|  | R0, R1, R2, R3, R4, R5, R6, R7, | 
|  | R8, R9, R10, R11, R12, R13, R14, | 
|  | R15, PC, PR, GBR, VBR, MACH, MACL, SR, | 
|  | TICKS, STALLS, CYCLES, INSTS, PLR | 
|  | }; | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | short *memAddr; | 
|  | short oldInstr; | 
|  | } | 
|  | stepData; | 
|  |  | 
|  | int registers[NUMREGBYTES / 4]; | 
|  | stepData instrBuffer; | 
|  | char stepped; | 
|  | static const char hexchars[] = "0123456789abcdef"; | 
|  | static char remcomInBuffer[BUFMAX]; | 
|  | static char remcomOutBuffer[BUFMAX]; | 
|  |  | 
|  | char highhex(int  x) | 
|  | { | 
|  | return hexchars[(x >> 4) & 0xf]; | 
|  | } | 
|  |  | 
|  | char lowhex(int  x) | 
|  | { | 
|  | return hexchars[x & 0xf]; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Assembly macros | 
|  | */ | 
|  |  | 
|  | #define BREAKPOINT()   asm("trapa	#0x20"::); | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Routines to handle hex data | 
|  | */ | 
|  |  | 
|  | static int | 
|  | hex (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); | 
|  | } | 
|  |  | 
|  | /* convert the memory, pointed to by mem into hex, placing result in buf */ | 
|  | /* return a pointer to the last char put in buf (null) */ | 
|  | static char * | 
|  | mem2hex (char *mem, char *buf, int count) | 
|  | { | 
|  | int i; | 
|  | int ch; | 
|  | for (i = 0; i < count; i++) | 
|  | { | 
|  | ch = *mem++; | 
|  | *buf++ = highhex (ch); | 
|  | *buf++ = lowhex (ch); | 
|  | } | 
|  | *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 char * | 
|  | hex2mem (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); | 
|  | } | 
|  |  | 
|  | /**********************************************/ | 
|  | /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ | 
|  | /* RETURN NUMBER OF CHARS PROCESSED           */ | 
|  | /**********************************************/ | 
|  | static 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); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Routines to get and put packets | 
|  | */ | 
|  |  | 
|  | /* scan for the sequence $<data>#<checksum>     */ | 
|  |  | 
|  | char * | 
|  | getpacket (void) | 
|  | { | 
|  | unsigned char *buffer = &remcomInBuffer[0]; | 
|  | unsigned char checksum; | 
|  | unsigned char xmitcsum; | 
|  | int count; | 
|  | char ch; | 
|  |  | 
|  | while (1) | 
|  | { | 
|  | /* wait around for the start character, ignore all other characters */ | 
|  | while ((ch = getDebugChar ()) != '$') | 
|  | ; | 
|  |  | 
|  | retry: | 
|  | checksum = 0; | 
|  | xmitcsum = -1; | 
|  | count = 0; | 
|  |  | 
|  | /* now, read until a # or end of buffer is found */ | 
|  | while (count < BUFMAX - 1) | 
|  | { | 
|  | ch = getDebugChar (); | 
|  | if (ch == '$') | 
|  | goto retry; | 
|  | if (ch == '#') | 
|  | break; | 
|  | checksum = checksum + ch; | 
|  | buffer[count] = ch; | 
|  | count = count + 1; | 
|  | } | 
|  | buffer[count] = 0; | 
|  |  | 
|  | if (ch == '#') | 
|  | { | 
|  | ch = getDebugChar (); | 
|  | xmitcsum = hex (ch) << 4; | 
|  | ch = getDebugChar (); | 
|  | xmitcsum += hex (ch); | 
|  |  | 
|  | 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]); | 
|  |  | 
|  | return &buffer[3]; | 
|  | } | 
|  |  | 
|  | return &buffer[0]; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* send the packet in buffer. */ | 
|  |  | 
|  | static void | 
|  | putpacket (char *buffer) | 
|  | { | 
|  | int checksum; | 
|  | int count; | 
|  |  | 
|  | /*  $<packet info>#<checksum>. */ | 
|  | do | 
|  | { | 
|  | char *src = buffer; | 
|  | putDebugChar ('$'); | 
|  | checksum = 0; | 
|  |  | 
|  | while (*src) | 
|  | { | 
|  | int runlen; | 
|  |  | 
|  | /* Do run length encoding */ | 
|  | for (runlen = 0; runlen < 100; runlen ++) | 
|  | { | 
|  | if (src[0] != src[runlen]) | 
|  | { | 
|  | if (runlen > 3) | 
|  | { | 
|  | int encode; | 
|  | /* Got a useful amount */ | 
|  | putDebugChar (*src); | 
|  | checksum += *src; | 
|  | putDebugChar ('*'); | 
|  | checksum += '*'; | 
|  | checksum += (encode = runlen + ' ' - 4); | 
|  | putDebugChar (encode); | 
|  | src += runlen; | 
|  | } | 
|  | else | 
|  | { | 
|  | putDebugChar (*src); | 
|  | checksum += *src; | 
|  | src++; | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | putDebugChar ('#'); | 
|  | putDebugChar (highhex(checksum)); | 
|  | putDebugChar (lowhex(checksum)); | 
|  | } | 
|  | while  (getDebugChar() != '+'); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* a bus error has occurred, perform a longjmp | 
|  | to return execution and allow handling of the error */ | 
|  |  | 
|  | void | 
|  | handle_buserror (void) | 
|  | { | 
|  | longjmp (remcomEnv, 1); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * this function takes the SH-1 exception number and attempts to | 
|  | * translate this number into a unix compatible signal value | 
|  | */ | 
|  | static int | 
|  | computeSignal (int exceptionVector) | 
|  | { | 
|  | int sigval; | 
|  | switch (exceptionVector) | 
|  | { | 
|  | case INVALID_INSN_VEC: | 
|  | sigval = 4; | 
|  | break; | 
|  | case INVALID_SLOT_VEC: | 
|  | sigval = 4; | 
|  | break; | 
|  | case CPU_BUS_ERROR_VEC: | 
|  | sigval = 10; | 
|  | break; | 
|  | case DMA_BUS_ERROR_VEC: | 
|  | sigval = 10; | 
|  | break; | 
|  | case NMI_VEC: | 
|  | sigval = 2; | 
|  | break; | 
|  |  | 
|  | case TRAP_VEC: | 
|  | case USER_VEC: | 
|  | sigval = 5; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | sigval = 7;		/* "software generated"*/ | 
|  | break; | 
|  | } | 
|  | return (sigval); | 
|  | } | 
|  |  | 
|  | void | 
|  | doSStep (void) | 
|  | { | 
|  | short *instrMem; | 
|  | int displacement; | 
|  | int reg; | 
|  | unsigned short opcode; | 
|  |  | 
|  | instrMem = (short *) registers[PC]; | 
|  |  | 
|  | opcode = *instrMem; | 
|  | stepped = 1; | 
|  |  | 
|  | if ((opcode & COND_BR_MASK) == BT_INSTR) | 
|  | { | 
|  | if (registers[SR] & T_BIT_MASK) | 
|  | { | 
|  | displacement = (opcode & COND_DISP) << 1; | 
|  | if (displacement & 0x80) | 
|  | displacement |= 0xffffff00; | 
|  | /* | 
|  | * Remember PC points to second instr. | 
|  | * after PC of branch ... so add 4 | 
|  | */ | 
|  | instrMem = (short *) (registers[PC] + displacement + 4); | 
|  | } | 
|  | else | 
|  | instrMem += 1; | 
|  | } | 
|  | else if ((opcode & COND_BR_MASK) == BF_INSTR) | 
|  | { | 
|  | if (registers[SR] & T_BIT_MASK) | 
|  | instrMem += 1; | 
|  | else | 
|  | { | 
|  | displacement = (opcode & COND_DISP) << 1; | 
|  | if (displacement & 0x80) | 
|  | displacement |= 0xffffff00; | 
|  | /* | 
|  | * Remember PC points to second instr. | 
|  | * after PC of branch ... so add 4 | 
|  | */ | 
|  | instrMem = (short *) (registers[PC] + displacement + 4); | 
|  | } | 
|  | } | 
|  | else if ((opcode & UCOND_DBR_MASK) == BRA_INSTR) | 
|  | { | 
|  | displacement = (opcode & UCOND_DISP) << 1; | 
|  | if (displacement & 0x0800) | 
|  | displacement |= 0xfffff000; | 
|  |  | 
|  | /* | 
|  | * Remember PC points to second instr. | 
|  | * after PC of branch ... so add 4 | 
|  | */ | 
|  | instrMem = (short *) (registers[PC] + displacement + 4); | 
|  | } | 
|  | else if ((opcode & UCOND_RBR_MASK) == JSR_INSTR) | 
|  | { | 
|  | reg = (char) ((opcode & UCOND_REG) >> 8); | 
|  |  | 
|  | instrMem = (short *) registers[reg]; | 
|  | } | 
|  | else if (opcode == RTS_INSTR) | 
|  | instrMem = (short *) registers[PR]; | 
|  | else if (opcode == RTE_INSTR) | 
|  | instrMem = (short *) registers[15]; | 
|  | else if ((opcode & TRAPA_MASK) == TRAPA_INSTR) | 
|  | instrMem = (short *) ((opcode & ~TRAPA_MASK) << 2); | 
|  | else | 
|  | instrMem += 1; | 
|  |  | 
|  | instrBuffer.memAddr = instrMem; | 
|  | instrBuffer.oldInstr = *instrMem; | 
|  | *instrMem = SSTEP_INSTR; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Undo the effect of a previous doSStep.  If we single stepped, | 
|  | restore the old instruction. */ | 
|  |  | 
|  | void | 
|  | undoSStep (void) | 
|  | { | 
|  | if (stepped) | 
|  | {  short *instrMem; | 
|  | instrMem = instrBuffer.memAddr; | 
|  | *instrMem = instrBuffer.oldInstr; | 
|  | } | 
|  | stepped = 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | This function does all exception handling.  It only does two things - | 
|  | it figures out why it was called and tells gdb, and then it reacts | 
|  | to gdb's requests. | 
|  |  | 
|  | When in the monitor mode we talk a human on the serial line rather than gdb. | 
|  |  | 
|  | */ | 
|  |  | 
|  |  | 
|  | void | 
|  | gdb_handle_exception (int exceptionVector) | 
|  | { | 
|  | int sigval, stepping; | 
|  | int addr, length; | 
|  | char *ptr; | 
|  |  | 
|  | /* reply to host that an exception has occurred */ | 
|  | sigval = computeSignal (exceptionVector); | 
|  | remcomOutBuffer[0] = 'S'; | 
|  | remcomOutBuffer[1] = highhex(sigval); | 
|  | remcomOutBuffer[2] = lowhex (sigval); | 
|  | remcomOutBuffer[3] = 0; | 
|  |  | 
|  | putpacket (remcomOutBuffer); | 
|  |  | 
|  | /* | 
|  | * exception 255 indicates a software trap | 
|  | * inserted in place of code ... so back up | 
|  | * PC by one instruction, since this instruction | 
|  | * will later be replaced by its original one! | 
|  | */ | 
|  | if (exceptionVector == 0xff | 
|  | || exceptionVector == 0x20) | 
|  | registers[PC] -= 2; | 
|  |  | 
|  | /* | 
|  | * Do the thangs needed to undo | 
|  | * any stepping we may have done! | 
|  | */ | 
|  | undoSStep (); | 
|  |  | 
|  | stepping = 0; | 
|  |  | 
|  | while (1) | 
|  | { | 
|  | remcomOutBuffer[0] = 0; | 
|  | ptr = getpacket (); | 
|  |  | 
|  | switch (*ptr++) | 
|  | { | 
|  | case '?': | 
|  | remcomOutBuffer[0] = 'S'; | 
|  | remcomOutBuffer[1] = highhex (sigval); | 
|  | remcomOutBuffer[2] = lowhex (sigval); | 
|  | 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 (ptr, (char *) registers, NUMREGBYTES); | 
|  | strcpy (remcomOutBuffer, "OK"); | 
|  | break; | 
|  |  | 
|  | /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */ | 
|  | case 'm': | 
|  | if (setjmp (remcomEnv) == 0) | 
|  | { | 
|  | dofault = 0; | 
|  | /* TRY, TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */ | 
|  | if (hexToInt (&ptr, &addr)) | 
|  | if (*(ptr++) == ',') | 
|  | if (hexToInt (&ptr, &length)) | 
|  | { | 
|  | ptr = 0; | 
|  | mem2hex ((char *) addr, remcomOutBuffer, length); | 
|  | } | 
|  | if (ptr) | 
|  | strcpy (remcomOutBuffer, "E01"); | 
|  | } | 
|  | else | 
|  | strcpy (remcomOutBuffer, "E03"); | 
|  |  | 
|  | /* restore handler for bus error */ | 
|  | dofault = 1; | 
|  | break; | 
|  |  | 
|  | /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ | 
|  | case 'M': | 
|  | if (setjmp (remcomEnv) == 0) | 
|  | { | 
|  | dofault = 0; | 
|  |  | 
|  | /* TRY, TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */ | 
|  | 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"); | 
|  | } | 
|  | else | 
|  | strcpy (remcomOutBuffer, "E03"); | 
|  |  | 
|  | /* restore handler for bus error */ | 
|  | dofault = 1; | 
|  | break; | 
|  |  | 
|  | /* cAA..AA    Continue at address AA..AA(optional) */ | 
|  | /* sAA..AA   Step one instruction from AA..AA(optional) */ | 
|  | case 's': | 
|  | stepping = 1; | 
|  | case 'c': | 
|  | { | 
|  | /* tRY, to read optional parameter, pc unchanged if no parm */ | 
|  | if (hexToInt (&ptr, &addr)) | 
|  | registers[PC] = addr; | 
|  |  | 
|  | if (stepping) | 
|  | doSStep (); | 
|  | } | 
|  | return; | 
|  | break; | 
|  |  | 
|  | /* kill the program */ | 
|  | case 'k':		/* do nothing */ | 
|  | break; | 
|  | }			/* switch */ | 
|  |  | 
|  | /* reply to the request */ | 
|  | putpacket (remcomOutBuffer); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | #define GDBCOOKIE 0x5ac | 
|  | static int ingdbmode; | 
|  | /* We've had an exception - choose to go into the monitor or | 
|  | the gdb stub */ | 
|  | void handle_exception(int exceptionVector) | 
|  | { | 
|  | #ifdef MONITOR | 
|  | if (ingdbmode != GDBCOOKIE) | 
|  | monitor_handle_exception (exceptionVector); | 
|  | else | 
|  | #endif | 
|  | gdb_handle_exception (exceptionVector); | 
|  |  | 
|  | } | 
|  |  | 
|  | void | 
|  | gdb_mode (void) | 
|  | { | 
|  | ingdbmode = GDBCOOKIE; | 
|  | breakpoint(); | 
|  | } | 
|  | /* 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 (void) | 
|  | { | 
|  | BREAKPOINT (); | 
|  | } | 
|  |  | 
|  | /**** Processor-specific routines start here ****/ | 
|  | /**** Processor-specific routines start here ****/ | 
|  | /**** Processor-specific routines start here ****/ | 
|  |  | 
|  | /* Note: | 
|  |  | 
|  | The Renesas SH family uses two exception architectures: | 
|  |  | 
|  | SH1 & SH2: | 
|  |  | 
|  | These processors utilize an exception vector table. | 
|  | Exceptions are vectored to the address stored at VBR + (exception_num * 4) | 
|  |  | 
|  | SH3, SH3E, & SH4: | 
|  |  | 
|  | These processors have fixed entry points relative to the VBR for | 
|  | various exception classes. | 
|  | */ | 
|  |  | 
|  | #if defined(__sh1__) || defined(__sh2__) | 
|  |  | 
|  | /* SH1/SH2 exception vector table format */ | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | void (*func_cold) (); | 
|  | int *stack_cold; | 
|  | void (*func_warm) (); | 
|  | int *stack_warm; | 
|  | void (*(handler[256 - 4])) (); | 
|  | } | 
|  | vec_type; | 
|  |  | 
|  | /* vectable is the SH1/SH2 vector table. It must be at address 0 | 
|  | or wherever your vbr points. */ | 
|  |  | 
|  | const vec_type vectable = | 
|  | { | 
|  | &BINIT,			/* 0: Power-on reset PC */ | 
|  | init_stack + init_stack_size, /* 1: Power-on reset SP */ | 
|  | &BINIT,			/* 2: Manual reset PC */ | 
|  | init_stack + init_stack_size, /* 3: Manual reset SP */ | 
|  | { | 
|  | &catch_exception_4,		/* 4: General invalid instruction */ | 
|  | &catch_exception_random,	/* 5: Reserved for system */ | 
|  | &catch_exception_6,		/* 6: Invalid slot instruction */ | 
|  | &catch_exception_random,	/* 7: Reserved for system */ | 
|  | &catch_exception_random,	/* 8: Reserved for system */ | 
|  | &catch_exception_9,		/* 9: CPU bus error */ | 
|  | &catch_exception_10,		/* 10: DMA bus error */ | 
|  | &catch_exception_11,		/* 11: NMI */ | 
|  | &catch_exception_random,	/* 12: User break */ | 
|  | &catch_exception_random,	/* 13: Reserved for system */ | 
|  | &catch_exception_random,	/* 14: Reserved for system */ | 
|  | &catch_exception_random,	/* 15: Reserved for system */ | 
|  | &catch_exception_random,	/* 16: Reserved for system */ | 
|  | &catch_exception_random,	/* 17: Reserved for system */ | 
|  | &catch_exception_random,	/* 18: Reserved for system */ | 
|  | &catch_exception_random,	/* 19: Reserved for system */ | 
|  | &catch_exception_random,	/* 20: Reserved for system */ | 
|  | &catch_exception_random,	/* 21: Reserved for system */ | 
|  | &catch_exception_random,	/* 22: Reserved for system */ | 
|  | &catch_exception_random,	/* 23: Reserved for system */ | 
|  | &catch_exception_random,	/* 24: Reserved for system */ | 
|  | &catch_exception_random,	/* 25: Reserved for system */ | 
|  | &catch_exception_random,	/* 26: Reserved for system */ | 
|  | &catch_exception_random,	/* 27: Reserved for system */ | 
|  | &catch_exception_random,	/* 28: Reserved for system */ | 
|  | &catch_exception_random,	/* 29: Reserved for system */ | 
|  | &catch_exception_random,	/* 30: Reserved for system */ | 
|  | &catch_exception_random,	/* 31: Reserved for system */ | 
|  | &catch_exception_32,		/* 32: Trap instr (user vectors) */ | 
|  | &catch_exception_33,		/* 33: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 34: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 35: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 36: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 37: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 38: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 39: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 40: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 41: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 42: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 43: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 44: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 45: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 46: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 47: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 48: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 49: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 50: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 51: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 52: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 53: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 54: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 55: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 56: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 57: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 58: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 59: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 60: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 61: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 62: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 63: Trap instr (user vectors) */ | 
|  | &catch_exception_random,	/* 64: IRQ0 */ | 
|  | &catch_exception_random,	/* 65: IRQ1 */ | 
|  | &catch_exception_random,	/* 66: IRQ2 */ | 
|  | &catch_exception_random,	/* 67: IRQ3 */ | 
|  | &catch_exception_random,	/* 68: IRQ4 */ | 
|  | &catch_exception_random,	/* 69: IRQ5 */ | 
|  | &catch_exception_random,	/* 70: IRQ6 */ | 
|  | &catch_exception_random,	/* 71: IRQ7 */ | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_random, | 
|  | &catch_exception_255}}; | 
|  |  | 
|  | #define BCR  (*(volatile short *)(0x05FFFFA0)) /* Bus control register */ | 
|  | #define BAS  (0x800)				/* Byte access select */ | 
|  | #define WCR1 (*(volatile short *)(0x05ffffA2)) /* Wait state control register */ | 
|  |  | 
|  | asm ("_BINIT: mov.l  L1,r15"); | 
|  | asm ("bra _INIT"); | 
|  | asm ("nop"); | 
|  | asm ("L1: .long _init_stack + 8*1024*4"); | 
|  | void | 
|  | INIT (void) | 
|  | { | 
|  | /* First turn on the ram */ | 
|  | WCR1  = 0;    /* Never sample wait */ | 
|  | BCR = BAS;    /* use lowbyte/high byte */ | 
|  |  | 
|  | init_serial(); | 
|  |  | 
|  | #ifdef MONITOR | 
|  | reset_hook (); | 
|  | #endif | 
|  |  | 
|  |  | 
|  | in_nmi = 0; | 
|  | dofault = 1; | 
|  | stepped = 0; | 
|  |  | 
|  | stub_sp = stub_stack + stub_stack_size; | 
|  | breakpoint (); | 
|  |  | 
|  | while (1) | 
|  | ; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void sr() | 
|  | { | 
|  |  | 
|  |  | 
|  | /* Calling Reset does the same as pressing the button */ | 
|  | asm (".global _Reset | 
|  | .global _WarmReset | 
|  | _Reset: | 
|  | _WarmReset: | 
|  | mov.l L_sp,r15 | 
|  | bra   _INIT | 
|  | nop | 
|  | .align 2 | 
|  | L_sp:    .long _init_stack + 8000"); | 
|  |  | 
|  | asm("saveRegisters: | 
|  | mov.l	@(L_reg, pc), r0 | 
|  | mov.l	@r15+, r1				! pop R0 | 
|  | mov.l	r2, @(0x08, r0)				! save R2 | 
|  | mov.l	r1, @r0					! save R0 | 
|  | mov.l	@r15+, r1				! pop R1 | 
|  | mov.l	r3, @(0x0c, r0)				! save R3 | 
|  | mov.l	r1, @(0x04, r0)				! save R1 | 
|  | mov.l	r4, @(0x10, r0)				! save R4 | 
|  | mov.l	r5, @(0x14, r0)				! save R5 | 
|  | mov.l	r6, @(0x18, r0)				! save R6 | 
|  | mov.l	r7, @(0x1c, r0)				! save R7 | 
|  | mov.l	r8, @(0x20, r0)				! save R8 | 
|  | mov.l	r9, @(0x24, r0)				! save R9 | 
|  | mov.l	r10, @(0x28, r0)			! save R10 | 
|  | mov.l	r11, @(0x2c, r0)			! save R11 | 
|  | mov.l	r12, @(0x30, r0)			! save R12 | 
|  | mov.l	r13, @(0x34, r0)			! save R13 | 
|  | mov.l	r14, @(0x38, r0)			! save R14 | 
|  | mov.l	@r15+, r4				! save arg to handleException | 
|  | add	#8, r15					! hide PC/SR values on stack | 
|  | mov.l	r15, @(0x3c, r0)			! save R15 | 
|  | add	#-8, r15				! save still needs old SP value | 
|  | add	#92, r0					! readjust register pointer | 
|  | mov	r15, r2 | 
|  | add	#4, r2 | 
|  | mov.l	@r2, r2					! R2 has SR | 
|  | mov.l	@r15, r1				! R1 has PC | 
|  | mov.l	r2, @-r0				! save SR | 
|  | sts.l	macl, @-r0				! save MACL | 
|  | sts.l	mach, @-r0				! save MACH | 
|  | stc.l	vbr, @-r0				! save VBR | 
|  | stc.l	gbr, @-r0				! save GBR | 
|  | sts.l	pr, @-r0				! save PR | 
|  | mov.l	@(L_stubstack, pc), r2 | 
|  | mov.l	@(L_hdl_except, pc), r3 | 
|  | mov.l	@r2, r15 | 
|  | jsr	@r3 | 
|  | mov.l	r1, @-r0				! save PC | 
|  | mov.l	@(L_stubstack, pc), r0 | 
|  | mov.l	@(L_reg, pc), r1 | 
|  | bra	restoreRegisters | 
|  | mov.l	r15, @r0				! save __stub_stack | 
|  |  | 
|  | .align 2 | 
|  | L_reg: | 
|  | .long	_registers | 
|  | L_stubstack: | 
|  | .long	_stub_sp | 
|  | L_hdl_except: | 
|  | .long	_handle_exception"); | 
|  |  | 
|  | } | 
|  |  | 
|  | static void rr() | 
|  | { | 
|  | asm(" | 
|  | .align 2 | 
|  | .global _resume | 
|  | _resume: | 
|  | mov	r4,r1 | 
|  | restoreRegisters: | 
|  | add	#8, r1						! skip to R2 | 
|  | mov.l	@r1+, r2					! restore R2 | 
|  | mov.l	@r1+, r3					! restore R3 | 
|  | mov.l	@r1+, r4					! restore R4 | 
|  | mov.l	@r1+, r5					! restore R5 | 
|  | mov.l	@r1+, r6					! restore R6 | 
|  | mov.l	@r1+, r7					! restore R7 | 
|  | mov.l	@r1+, r8					! restore R8 | 
|  | mov.l	@r1+, r9					! restore R9 | 
|  | mov.l	@r1+, r10					! restore R10 | 
|  | mov.l	@r1+, r11					! restore R11 | 
|  | mov.l	@r1+, r12					! restore R12 | 
|  | mov.l	@r1+, r13					! restore R13 | 
|  | mov.l	@r1+, r14					! restore R14 | 
|  | mov.l	@r1+, r15					! restore programs stack | 
|  | mov.l	@r1+, r0 | 
|  | add	#-8, r15					! uncover PC/SR on stack | 
|  | mov.l	r0, @r15					! restore PC onto stack | 
|  | lds.l	@r1+, pr					! restore PR | 
|  | ldc.l	@r1+, gbr					! restore GBR | 
|  | ldc.l	@r1+, vbr					! restore VBR | 
|  | lds.l	@r1+, mach					! restore MACH | 
|  | lds.l	@r1+, macl					! restore MACL | 
|  | mov.l	@r1, r0 | 
|  | add	#-88, r1					! readjust reg pointer to R1 | 
|  | mov.l	r0, @(4, r15)					! restore SR onto stack+4 | 
|  | mov.l	r2, @-r15 | 
|  | mov.l	L_in_nmi, r0 | 
|  | mov		#0, r2 | 
|  | mov.b	r2, @r0 | 
|  | mov.l	@r15+, r2 | 
|  | mov.l	@r1+, r0					! restore R0 | 
|  | rte | 
|  | mov.l	@r1, r1						! restore R1 | 
|  |  | 
|  | "); | 
|  | } | 
|  |  | 
|  |  | 
|  | static __inline__ void code_for_catch_exception(int n) | 
|  | { | 
|  | asm("		.globl	_catch_exception_%O0" : : "i" (n) 				); | 
|  | asm("	_catch_exception_%O0:" :: "i" (n)      						); | 
|  |  | 
|  | asm("		add	#-4, r15 				! reserve spot on stack "); | 
|  | asm("		mov.l	r1, @-r15				! push R1		"); | 
|  |  | 
|  | if (n == NMI_VEC) | 
|  | { | 
|  | /* Special case for NMI - make sure that they don't nest */ | 
|  | asm("	mov.l	r0, @-r15					! push R0"); | 
|  | asm("	mov.l	L_in_nmi, r0"); | 
|  | asm("	tas.b	@r0						! Fend off against addtnl NMIs"); | 
|  | asm("	bt		noNMI"); | 
|  | asm("	mov.l	@r15+, r0"); | 
|  | asm("	mov.l	@r15+, r1"); | 
|  | asm("	add		#4, r15"); | 
|  | asm("	rte"); | 
|  | asm("	nop"); | 
|  | asm(".align 2"); | 
|  | asm("L_in_nmi: .long	_in_nmi"); | 
|  | asm("noNMI:"); | 
|  | } | 
|  | else | 
|  | { | 
|  |  | 
|  | if (n == CPU_BUS_ERROR_VEC) | 
|  | { | 
|  | /* Exception 9 (bus errors) are disasbleable - so that you | 
|  | can probe memory and get zero instead of a fault. | 
|  | Because the vector table may be in ROM we don't revector | 
|  | the interrupt like all the other stubs, we check in here | 
|  | */ | 
|  | asm("mov.l	L_dofault,r1"); | 
|  | asm("mov.l	@r1,r1"); | 
|  | asm("tst	r1,r1"); | 
|  | asm("bf	faultaway"); | 
|  | asm("bsr	_handle_buserror"); | 
|  | asm(".align	2"); | 
|  | asm("L_dofault: .long _dofault"); | 
|  | asm("faultaway:"); | 
|  | } | 
|  | asm("		mov	#15<<4, r1							"); | 
|  | asm("		ldc	r1, sr					! disable interrupts	"); | 
|  | asm("		mov.l	r0, @-r15				! push R0		"); | 
|  | } | 
|  |  | 
|  | /* Prepare for saving context, we've already pushed r0 and r1, stick exception number | 
|  | into the frame */ | 
|  | asm("		mov	r15, r0								"); | 
|  | asm("		add	#8, r0								"); | 
|  | asm("		mov	%0,r1" :: "i" (n)        					); | 
|  | asm("		extu.b  r1,r1								"); | 
|  | asm("		bra	saveRegisters				! save register values	"); | 
|  | asm("		mov.l	r1, @r0					! save exception # 	"); | 
|  | } | 
|  |  | 
|  |  | 
|  | static  void | 
|  | exceptions (void) | 
|  | { | 
|  | code_for_catch_exception (CPU_BUS_ERROR_VEC); | 
|  | code_for_catch_exception (DMA_BUS_ERROR_VEC); | 
|  | code_for_catch_exception (INVALID_INSN_VEC); | 
|  | code_for_catch_exception (INVALID_SLOT_VEC); | 
|  | code_for_catch_exception (NMI_VEC); | 
|  | code_for_catch_exception (TRAP_VEC); | 
|  | code_for_catch_exception (USER_VEC); | 
|  | code_for_catch_exception (IO_VEC); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | /* Support for Serial I/O using on chip uart */ | 
|  |  | 
|  | #define SMR0 (*(volatile char *)(0x05FFFEC0)) /* Channel 0  serial mode register */ | 
|  | #define BRR0 (*(volatile char *)(0x05FFFEC1)) /* Channel 0  bit rate register */ | 
|  | #define SCR0 (*(volatile char *)(0x05FFFEC2)) /* Channel 0  serial control register */ | 
|  | #define TDR0 (*(volatile char *)(0x05FFFEC3)) /* Channel 0  transmit data register */ | 
|  | #define SSR0 (*(volatile char *)(0x05FFFEC4)) /* Channel 0  serial status register */ | 
|  | #define RDR0 (*(volatile char *)(0x05FFFEC5)) /* Channel 0  receive data register */ | 
|  |  | 
|  | #define SMR1 (*(volatile char *)(0x05FFFEC8)) /* Channel 1  serial mode register */ | 
|  | #define BRR1 (*(volatile char *)(0x05FFFEC9)) /* Channel 1  bit rate register */ | 
|  | #define SCR1 (*(volatile char *)(0x05FFFECA)) /* Channel 1  serial control register */ | 
|  | #define TDR1 (*(volatile char *)(0x05FFFECB)) /* Channel 1  transmit data register */ | 
|  | #define SSR1 (*(volatile char *)(0x05FFFECC)) /* Channel 1  serial status register */ | 
|  | #define RDR1 (*(volatile char *)(0x05FFFECD)) /* Channel 1  receive data register */ | 
|  |  | 
|  | /* | 
|  | * Serial mode register bits | 
|  | */ | 
|  |  | 
|  | #define SYNC_MODE 		0x80 | 
|  | #define SEVEN_BIT_DATA 		0x40 | 
|  | #define PARITY_ON		0x20 | 
|  | #define ODD_PARITY		0x10 | 
|  | #define STOP_BITS_2		0x08 | 
|  | #define ENABLE_MULTIP		0x04 | 
|  | #define PHI_64			0x03 | 
|  | #define PHI_16			0x02 | 
|  | #define PHI_4			0x01 | 
|  |  | 
|  | /* | 
|  | * Serial control register bits | 
|  | */ | 
|  | #define SCI_TIE				0x80	/* Transmit interrupt enable */ | 
|  | #define SCI_RIE				0x40	/* Receive interrupt enable */ | 
|  | #define SCI_TE				0x20	/* Transmit enable */ | 
|  | #define SCI_RE				0x10	/* Receive enable */ | 
|  | #define SCI_MPIE			0x08	/* Multiprocessor interrupt enable */ | 
|  | #define SCI_TEIE			0x04	/* Transmit end interrupt enable */ | 
|  | #define SCI_CKE1			0x02	/* Clock enable 1 */ | 
|  | #define SCI_CKE0			0x01	/* Clock enable 0 */ | 
|  |  | 
|  | /* | 
|  | * Serial status register bits | 
|  | */ | 
|  | #define SCI_TDRE			0x80	/* Transmit data register empty */ | 
|  | #define SCI_RDRF			0x40	/* Receive data register full */ | 
|  | #define SCI_ORER			0x20	/* Overrun error */ | 
|  | #define SCI_FER				0x10	/* Framing error */ | 
|  | #define SCI_PER				0x08	/* Parity error */ | 
|  | #define SCI_TEND			0x04	/* Transmit end */ | 
|  | #define SCI_MPB				0x02	/* Multiprocessor bit */ | 
|  | #define SCI_MPBT			0x01	/* Multiprocessor bit transfer */ | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Port B IO Register (PBIOR) | 
|  | */ | 
|  | #define	PBIOR 		(*(volatile char *)(0x05FFFFC6)) | 
|  | #define	PB15IOR 	0x8000 | 
|  | #define	PB14IOR 	0x4000 | 
|  | #define	PB13IOR 	0x2000 | 
|  | #define	PB12IOR 	0x1000 | 
|  | #define	PB11IOR 	0x0800 | 
|  | #define	PB10IOR 	0x0400 | 
|  | #define	PB9IOR 		0x0200 | 
|  | #define	PB8IOR 		0x0100 | 
|  | #define	PB7IOR 		0x0080 | 
|  | #define	PB6IOR 		0x0040 | 
|  | #define	PB5IOR 		0x0020 | 
|  | #define	PB4IOR 		0x0010 | 
|  | #define	PB3IOR 		0x0008 | 
|  | #define	PB2IOR 		0x0004 | 
|  | #define	PB1IOR 		0x0002 | 
|  | #define	PB0IOR 		0x0001 | 
|  |  | 
|  | /* | 
|  | * Port B Control Register (PBCR1) | 
|  | */ | 
|  | #define	PBCR1 		(*(volatile short *)(0x05FFFFCC)) | 
|  | #define	PB15MD1 	0x8000 | 
|  | #define	PB15MD0 	0x4000 | 
|  | #define	PB14MD1 	0x2000 | 
|  | #define	PB14MD0 	0x1000 | 
|  | #define	PB13MD1 	0x0800 | 
|  | #define	PB13MD0 	0x0400 | 
|  | #define	PB12MD1 	0x0200 | 
|  | #define	PB12MD0 	0x0100 | 
|  | #define	PB11MD1 	0x0080 | 
|  | #define	PB11MD0 	0x0040 | 
|  | #define	PB10MD1 	0x0020 | 
|  | #define	PB10MD0 	0x0010 | 
|  | #define	PB9MD1 		0x0008 | 
|  | #define	PB9MD0 		0x0004 | 
|  | #define	PB8MD1 		0x0002 | 
|  | #define	PB8MD0 		0x0001 | 
|  |  | 
|  | #define	PB15MD 		PB15MD1|PB14MD0 | 
|  | #define	PB14MD 		PB14MD1|PB14MD0 | 
|  | #define	PB13MD 		PB13MD1|PB13MD0 | 
|  | #define	PB12MD 		PB12MD1|PB12MD0 | 
|  | #define	PB11MD 		PB11MD1|PB11MD0 | 
|  | #define	PB10MD 		PB10MD1|PB10MD0 | 
|  | #define	PB9MD 		PB9MD1|PB9MD0 | 
|  | #define	PB8MD 		PB8MD1|PB8MD0 | 
|  |  | 
|  | #define PB_TXD1 	PB11MD1 | 
|  | #define PB_RXD1 	PB10MD1 | 
|  | #define PB_TXD0 	PB9MD1 | 
|  | #define PB_RXD0 	PB8MD1 | 
|  |  | 
|  | /* | 
|  | * Port B Control Register (PBCR2) | 
|  | */ | 
|  | #define	PBCR2 	0x05FFFFCE | 
|  | #define	PB7MD1 	0x8000 | 
|  | #define	PB7MD0 	0x4000 | 
|  | #define	PB6MD1 	0x2000 | 
|  | #define	PB6MD0 	0x1000 | 
|  | #define	PB5MD1 	0x0800 | 
|  | #define	PB5MD0 	0x0400 | 
|  | #define	PB4MD1 	0x0200 | 
|  | #define	PB4MD0 	0x0100 | 
|  | #define	PB3MD1 	0x0080 | 
|  | #define	PB3MD0 	0x0040 | 
|  | #define	PB2MD1 	0x0020 | 
|  | #define	PB2MD0 	0x0010 | 
|  | #define	PB1MD1 	0x0008 | 
|  | #define	PB1MD0 	0x0004 | 
|  | #define	PB0MD1 	0x0002 | 
|  | #define	PB0MD0 	0x0001 | 
|  |  | 
|  | #define	PB7MD 	PB7MD1|PB7MD0 | 
|  | #define	PB6MD 	PB6MD1|PB6MD0 | 
|  | #define	PB5MD 	PB5MD1|PB5MD0 | 
|  | #define	PB4MD 	PB4MD1|PB4MD0 | 
|  | #define	PB3MD 	PB3MD1|PB3MD0 | 
|  | #define	PB2MD 	PB2MD1|PB2MD0 | 
|  | #define	PB1MD 	PB1MD1|PB1MD0 | 
|  | #define	PB0MD 	PB0MD1|PB0MD0 | 
|  |  | 
|  |  | 
|  | #ifdef MHZ | 
|  | #define BPS			32 * 9600 * MHZ / ( BAUD * 10) | 
|  | #else | 
|  | #define BPS			32	/* 9600 for 10 Mhz */ | 
|  | #endif | 
|  |  | 
|  | void handleError (char theSSR); | 
|  |  | 
|  | void | 
|  | nop (void) | 
|  | { | 
|  |  | 
|  | } | 
|  | void | 
|  | init_serial (void) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | /* Clear TE and RE in Channel 1's SCR   */ | 
|  | SCR1 &= ~(SCI_TE | SCI_RE); | 
|  |  | 
|  | /* Set communication to be async, 8-bit data, no parity, 1 stop bit and use internal clock */ | 
|  |  | 
|  | SMR1 = 0; | 
|  | BRR1 = BPS; | 
|  |  | 
|  | SCR1 &= ~(SCI_CKE1 | SCI_CKE0); | 
|  |  | 
|  | /* let the hardware settle */ | 
|  |  | 
|  | for (i = 0; i < 1000; i++) | 
|  | nop (); | 
|  |  | 
|  | /* Turn on in and out */ | 
|  | SCR1 |= SCI_RE | SCI_TE; | 
|  |  | 
|  | /* Set the PFC to make RXD1 (pin PB8) an input pin and TXD1 (pin PB9) an output pin */ | 
|  | PBCR1 &= ~(PB_TXD1 | PB_RXD1); | 
|  | PBCR1 |= PB_TXD1 | PB_RXD1; | 
|  | } | 
|  |  | 
|  |  | 
|  | int | 
|  | getDebugCharReady (void) | 
|  | { | 
|  | char mySSR; | 
|  | mySSR = SSR1 & ( SCI_PER | SCI_FER | SCI_ORER ); | 
|  | if ( mySSR ) | 
|  | handleError ( mySSR ); | 
|  | return SSR1 & SCI_RDRF ; | 
|  | } | 
|  |  | 
|  | char | 
|  | getDebugChar (void) | 
|  | { | 
|  | char ch; | 
|  | char mySSR; | 
|  |  | 
|  | while ( ! getDebugCharReady()) | 
|  | ; | 
|  |  | 
|  | ch = RDR1; | 
|  | SSR1 &= ~SCI_RDRF; | 
|  |  | 
|  | mySSR = SSR1 & (SCI_PER | SCI_FER | SCI_ORER); | 
|  |  | 
|  | if (mySSR) | 
|  | handleError (mySSR); | 
|  |  | 
|  | return ch; | 
|  | } | 
|  |  | 
|  | int | 
|  | putDebugCharReady (void) | 
|  | { | 
|  | return (SSR1 & SCI_TDRE); | 
|  | } | 
|  |  | 
|  | void | 
|  | putDebugChar (char ch) | 
|  | { | 
|  | while (!putDebugCharReady()) | 
|  | ; | 
|  |  | 
|  | /* | 
|  | * Write data into TDR and clear TDRE | 
|  | */ | 
|  | TDR1 = ch; | 
|  | SSR1 &= ~SCI_TDRE; | 
|  | } | 
|  |  | 
|  | void | 
|  | handleError (char theSSR) | 
|  | { | 
|  | SSR1 &= ~(SCI_ORER | SCI_PER | SCI_FER); | 
|  | } | 
|  |  | 
|  | #endif |