| /* 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 |