diff options
Diffstat (limited to 'c/src/lib/libbsp/m68k/efi68k/startup')
-rw-r--r-- | c/src/lib/libbsp/m68k/efi68k/startup/bspclean.c | 28 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/efi68k/startup/bspstart.c | 230 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/efi68k/startup/efi68k_tcp.c | 248 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/efi68k/startup/efi68k_wd.c | 55 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/efi68k/startup/linkcmds | 108 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/efi68k/startup/m68k-stub.c | 782 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/efi68k/startup/setvec.c | 45 |
7 files changed, 1496 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/m68k/efi68k/startup/bspclean.c b/c/src/lib/libbsp/m68k/efi68k/startup/bspclean.c new file mode 100644 index 0000000000..34a57b6b68 --- /dev/null +++ b/c/src/lib/libbsp/m68k/efi68k/startup/bspclean.c @@ -0,0 +1,28 @@ +/* bsp_cleanup() + * + * This routine cleans up in the sense that it places the board + * in a safe state and flushes the I/O buffers before exiting. + * + * INPUT: NONE + * + * OUTPUT: NONE + * + * COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994. + * On-Line Applications Research Corporation (OAR). + * All rights assigned to U.S. Government, 1994. + * + * This material may be reproduced by or for the U.S. Government pursuant + * to the copyright license under the clause at DFARS 252.227-7013. This + * notice must appear in all copies of this file and its derivatives. + * + * $Id$ + */ + +#include <bsp.h> + +void bsp_cleanup(void) +{ + /* interrupt driven stdio must be flushed */ + _CPU_ISR_Set_level( 7 ); + _UART_flush(); +} diff --git a/c/src/lib/libbsp/m68k/efi68k/startup/bspstart.c b/c/src/lib/libbsp/m68k/efi68k/startup/bspstart.c new file mode 100644 index 0000000000..e08f78baff --- /dev/null +++ b/c/src/lib/libbsp/m68k/efi68k/startup/bspstart.c @@ -0,0 +1,230 @@ +#define STACK_CHECKER_ON +/* bsp_start() + * + * This routine starts the application. It includes application, + * board, and monitor specific initialization and configuration. + * The generic CPU dependent initialization has been performed + * before this routine is invoked. + * + * INPUT: NONE + * + * OUTPUT: NONE + * + * COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994. + * On-Line Applications Research Corporation (OAR). + * All rights assigned to U.S. Government, 1994. + * + * This material may be reproduced by or for the U.S. Government pursuant + * to the copyright license under the clause at DFARS 252.227-7013. This + * notice must appear in all copies of this file and its derivatives. + * + * $Id$ + */ + +#include <stdlib.h> +#include <bsp.h> +#include <rtems/libio.h> +#include <libcsupport.h> + +#include <string.h> +#include <fcntl.h> + +#ifdef STACK_CHECKER_ON +#include <stackchk.h> +#endif + +/* + * The original table from the application and our copy of it with + * some changes. + */ + +extern rtems_configuration_table Configuration; +rtems_configuration_table BSP_Configuration; + +rtems_cpu_table Cpu_table; + +char *rtems_progname; + +rtems_unsigned32 Timer_interrupts; + +/* extern void set_debug_traps(void); */ +/* extern void breakpoint(void); */ + +/* Initialize whatever libc we are using + * called from postdriver hook + */ + +void bsp_libc_init() +{ + extern int end; + rtems_unsigned32 heap_start; + + heap_start = (rtems_unsigned32) &end; + if (heap_start & (CPU_ALIGNMENT-1)) + heap_start = (heap_start + CPU_ALIGNMENT) & ~(CPU_ALIGNMENT-1); + + RTEMS_Malloc_Initialize((void *) heap_start, 64 * 1024, 0); + + /* + * Init the RTEMS libio facility to provide UNIX-like system + * calls for use by newlib (ie: provide __open, __close, etc) + * Uses malloc() to get area for the iops, so must be after malloc init + */ + + rtems_libio_init(); + + /* + * Set up for the libc handling. + */ + + if (BSP_Configuration.ticks_per_timeslice > 0) + libc_init(1); /* reentrant if possible */ + else + libc_init(0); /* non-reentrant */ + +} + +/* + * Function: bsp_pretasking_hook + * Created: 95/03/10 + * + * Description: + * BSP pretasking hook. Called just before drivers are initialized. + * Used to setup libc and install any BSP extensions. + * + * NOTES: + * Must not use libc (to do io) from here, since drivers are + * not yet initialized. + * + */ + +void +bsp_pretasking_hook(void) +{ + bsp_libc_init(); + +#ifdef STACK_CHECKER_ON + /* + * Initialize the stack bounds checker + * We can either turn it on here or from the app. + */ + + Stack_check_Initialize(); +#endif + +#ifdef RTEMS_DEBUG + rtems_debug_enable( RTEMS_DEBUG_ALL_MASK ); +#endif +} + + +/* + * After drivers are setup, register some "filenames" + * and open stdin, stdout, stderr files + * + * Newlib will automatically associate the files with these + * (it hardcodes the numbers) + */ + +void +bsp_postdriver_hook(void) +{ + int stdin_fd, stdout_fd, stderr_fd; + + if ((stdin_fd = __open("/dev/console", O_RDONLY, 0)) == -1) + rtems_fatal_error_occurred('STD0'); + + if ((stdout_fd = __open("/dev/console", O_WRONLY, 0)) == -1) + rtems_fatal_error_occurred('STD1'); + + if ((stderr_fd = __open("/dev/console", O_WRONLY, 0)) == -1) + rtems_fatal_error_occurred('STD2'); + + if ((stdin_fd != 0) || (stdout_fd != 1) || (stderr_fd != 2)) + rtems_fatal_error_occurred('STIO'); +} + +int main( + int argc, + char **argv, + char **environp +) +{ + void *vbr; + +/* set_debug_traps(); */ +/* breakpoint(); */ + + /* + * we only use a hook to get the C library initialized. + */ + + Cpu_table.pretasking_hook = bsp_pretasking_hook; /* init libc, etc. */ + + Cpu_table.predriver_hook = NULL; + + Cpu_table.postdriver_hook = bsp_postdriver_hook; + + Cpu_table.idle_task = NULL; /* do not override system IDLE task */ + + Cpu_table.do_zero_of_workspace = TRUE; + + m68k_get_vbr( vbr ); + Cpu_table.interrupt_vector_table = vbr; + + Cpu_table.interrupt_stack_size = 4096; + + Cpu_table.extra_system_initialization_stack = 0; + + /* + * Copy the table + */ + + BSP_Configuration = Configuration; + + BSP_Configuration.work_space_start = (void *) + (RAM_END - BSP_Configuration.work_space_size); + + if ((unsigned int)BSP_Configuration.work_space_start < + (unsigned int)((stack_start + stack_size) & 0xffffffc0) ) { + /* rtems_fatal_error_occurred can not be used before initalization */ + RAW_PUTS("\n\rRTEMS: Out of memory.\n\r"); + RAW_PUTS("RTEMS: Check RAM_END and the size of the work space.\n\r"); + goto exit; + } + + /* + * Add 1 region for Malloc in libc_low + */ + + BSP_Configuration.maximum_regions++; + + /* + * Add 1 extension for newlib libc + */ + +#ifdef RTEMS_NEWLIB + BSP_Configuration.maximum_extensions++; +#endif + + /* + * Add another extension if using the stack checker + */ + +#ifdef STACK_CHECKER_ON + BSP_Configuration.maximum_extensions++; +#endif + + rtems_initialize_executive( &BSP_Configuration, &Cpu_table ); + /* does not return */ + + /* Clock_exit is done as an atexit() function */ + +exit: + /* configure peripherals for safe exit */ + bsp_cleanup(); + + /* return like a "normal" subroutine to the monitor */ + return 0; +} + diff --git a/c/src/lib/libbsp/m68k/efi68k/startup/efi68k_tcp.c b/c/src/lib/libbsp/m68k/efi68k/startup/efi68k_tcp.c new file mode 100644 index 0000000000..9dd4836b25 --- /dev/null +++ b/c/src/lib/libbsp/m68k/efi68k/startup/efi68k_tcp.c @@ -0,0 +1,248 @@ +/* + *------------------------------------------------------------------- + * + * This file contains the subroutines necessary to initalize + * the DP8750A TCP on the efi68k board. + * + * This file has been created by John S. Gwynne for the efi68k + * project. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. Redistribution of source code and documentation must retain + * the above authorship, this list of conditions and the + * following disclaimer. + * 2. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * This software is provided "AS IS" without warranty of any kind, + * either expressed or implied, including, but not limited to, the + * implied warranties of merchantability, title and fitness for a + * particular purpose. + * + *------------------------------------------------------------------ + * + * $Id$ + */ + +#include <bsp.h> + +/* define tcp struct pointers */ +struct clock_ram * const tcp_power_up = + (struct clock_ram * const)(0x16*2+TCP_BASE_ADDRESS); + +struct clock_ram * const tcp_power_down = + (struct clock_ram * const)(0x1b*2+TCP_BASE_ADDRESS); + +struct clock_counters * const tcp_clock = + (struct clock_counters * const)(0x05*2+TCP_BASE_ADDRESS); + +struct clock_ram * const tcp_save_ram = + (struct clock_ram * const)(0x19*2+TCP_BASE_ADDRESS); + +#define X_DELAY 300 /* time-out delay for crystal start */ +#define X1_DELAY 100000 + +void tcp_delay(int count) +{ + int i; + /* change latter to use a counter !!! */ + for (i=0;i<count/4;i++); +} + +void tcp_init() +{ + unsigned char low_bat, osc_fail, power_up; + unsigned char mon, dom, hrs, min, sec; + int i, count; + + /* delay about 60us to ensure TCP is not locked-out */ + tcp_delay(80); + + /* set normal supply mode and reset test mode bit */ + *MSR = 0; + *PFR = 0; + + /* save oscillator failure condition */ + *MSR = 0; /* set RS and PS to zero */ + osc_fail = (*PFR & OSF ? 1 : 0); + *MSR = PS; + *RAM_OSC_FAIL = *RAM_OSC_FAIL || osc_fail; + + *MSR = PS; + if (*RAM_OSC_FAIL) { + power_up = 1; + *MSR = PS; + *RAM_POWERUP = power_up; + /* clear time counters and power up & down ram */ + *MSR = 0; + tcp_clock->hofs = 0; + tcp_clock->sec = 0; + tcp_clock->min = 0; + tcp_clock->hrs = 0; + tcp_clock->dom = 1; + tcp_clock->mon = 1; + tcp_clock->yr = 0x95; + tcp_clock->jd0 = 0x01; + tcp_clock->jd1 = 0; + tcp_clock->dow = 1; + *MSR = PS; + tcp_power_up->sec = 0; + tcp_power_up->min = 0; + tcp_power_up->hrs = 0; + tcp_power_up->dom = 0; + tcp_power_up->mon = 0; + tcp_power_down->sec = 0; + tcp_power_down->min = 0; + tcp_power_down->hrs = 0; + tcp_power_down->dom = 0; + tcp_power_down->mon = 0; + } else { + /* save for power-up test */ + *MSR = 0; + power_up = (*IRR & TMSE ? 0 : 1); + *MSR = PS; + *RAM_POWERUP = power_up; + + /* update tcp_power_up and tcp_power_down on power up */ + if (power_up) { + *MSR = 0; + do { + *PFR; + sec = tcp_clock->sec; + min = tcp_clock->min; + hrs = tcp_clock->hrs; + dom = tcp_clock->dom; + mon = tcp_clock->mon; + } while (*PFR & R_1S); + *MSR = PS; + tcp_power_up->sec = sec; + tcp_power_up->min = min; + tcp_power_up->hrs = hrs; + tcp_power_up->dom = dom; + tcp_power_up->mon = ( (((mon>>4)*10)+(mon&0xf))>12 ? 0 : mon ); + *MSR = 0; /* save ram is not running */ + sec = tcp_save_ram->sec; + min = tcp_save_ram->min; + hrs = tcp_save_ram->hrs; + dom = tcp_save_ram->dom; + mon = tcp_save_ram->mon; + *MSR = PS; + tcp_power_down->sec = sec; + tcp_power_down->min = min; + tcp_power_down->hrs = hrs; + tcp_power_down->dom = dom; + tcp_power_down->mon = ( (((mon>>4)*10)+(mon&0xf))>12 ? 0 : mon ); + } + } + + /* load interrupt routing reg. PF must be enabled to test + for low battery, but I route it to MFO to avoid any + potential problems */ + *MSR = 0; + *IRR = PF_R | TMSE; + + /* initialize the output mode register */ + *MSR = RS; + *OMR = IP | MP | MO; /* INTR active low and push/pull */ + + /* initialize interrupt control reg 0 */ + *MSR = RS; + *ICR0 = 0; /* disable all interrupts */ + + /* initialize interrupt control reg 1 */ + *MSR = RS; + *ICR1 = PFE; /* this also enables the low battery + detection circuit. */ + + /* I had trouble getting the tcp to be completely + flexabale to supply modes (i.e., automatically + selecting single or normal battery backup modes based + on inputs at power-up. If single supply mode is + selected, the low battery detect is disabled and the + low battery detect in normal mode does not seem to + detect when no battery is present at all. If normal + mode is selected and no battery is present, the + crystal will stop, but only if reset after + power-up. It would seem that after a power-up reset, + with no battery, the chip may automaticlly switch to + single supply mode which disables the low battery + detection circuit.) The following software tests + works for all permiatations of low batt, reset, + power-on reset, battery, no battery, battery on after + Vcc,.... *except* for battery switched on for the + first time before power up in which case the chip + will still be in single suppy mode till restarted (a + second call to tcp_init such as when the time is set + or a reboot.) The timer/clock itself should always + be completely functional regardless of the supply + mode. */ + + + /* initialize the real time mode register */ + /* note: write mode bits *before* CSS, then set CSS */ + *MSR = 0; /* clear roll-over */ + *PFR; + count=1; + for (i=0;i<X_DELAY;i++) { /* loop till xtal starts */ + *MSR = RS; + *RTMR = (*RTMR & (LY0 | LY1 )) | CSS; + *MSR = 0; + if (*PFR & R_1MS) + if (!(count--)) break; + } + if (i>=X_DELAY) { + { + /* xtal didn't start; try single supply mode */ + *MSR = 0; /* single supply */ + *PFR = OSF; + *MSR = 0; /* clear roll-over */ + *PFR; + count=1; + for (i=0;i<X1_DELAY;i++) { /* loop till xtal starts */ + *MSR = RS; + *RTMR = (*RTMR & (LY0 | LY1 )) | CSS; + *MSR = 0; + if (*PFR & R_1MS) + if (!(count--)) break; + } + if (i>=X1_DELAY) { + /* xtal didn't start; fail tcp */ + *MSR = PS; + *RAM_TCP_FAILURE = 1; + *MSR = PS; + *RAM_SINGLE_SUP=1; + } else { + *MSR = PS; + *RAM_TCP_FAILURE = 0; + *MSR = PS; + *RAM_SINGLE_SUP=1; + } + } + } else { + *MSR = PS; + *RAM_TCP_FAILURE = 0; + *MSR = PS; + *RAM_SINGLE_SUP=0; + } + + /* wait for low battery detection circuit to stabalize */ + tcp_delay(1000); + + /* battery test */ + *MSR = 0; + low_bat = (*IRR & LBF ? 1 : 0 ); + *MSR = PS; + *RAM_LOWBAT = low_bat & !(*RAM_SINGLE_SUP); + + /* reset pending interrupts */ + *MSR = ( PER | AL | T0 | T1 ); + + /* resync the time save ram with the clock */ + tcp_save_ram->sec = 0; + tcp_save_ram->min = 0; + tcp_save_ram->hrs = 0; + tcp_save_ram->dom = 0; + tcp_save_ram->mon = 0; +} diff --git a/c/src/lib/libbsp/m68k/efi68k/startup/efi68k_wd.c b/c/src/lib/libbsp/m68k/efi68k/startup/efi68k_wd.c new file mode 100644 index 0000000000..0ad4d87b82 --- /dev/null +++ b/c/src/lib/libbsp/m68k/efi68k/startup/efi68k_wd.c @@ -0,0 +1,55 @@ +/* + *------------------------------------------------------------------- + * + * This file contains the subroutines necessary to initalize + * and maintain the MAX791 based watchdog timer used on efi68k + * + * This file has been created by John S. Gwynne for the efi68k + * project. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. Redistribution of source code and documentation must retain + * the above authorship, this list of conditions and the + * following disclaimer. + * 2. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * This software is provided "AS IS" without warranty of any kind, + * either expressed or implied, including, but not limited to, the + * implied warranties of merchantability, title and fitness for a + * particular purpose. + * + *------------------------------------------------------------------ + * + * $Id$ + */ +#include <bsp.h> + +void wd_interrupt(void) { + /* toggle WDI of the MAX791. A more sophisticated routine + can be inserted into the exception table after booting. */ + + /* 3 changes guaranty a pulse independent of initial state */ + *MCR |= OUT1; + *MCR &= ~OUT1; + *MCR |= OUT1; +} + +/* _catchWDint is the interrupt front-end */ +extern void _catchWDint(); +asm(" .text + .align 2 + .globl _catchWDint +_catchWDint: + lea %sp@(4),%sp /* pop return address */ + moveml %d0-%d7/%a0-%a6,%sp@- /* save registers */ + jbsr wd_interrupt + moveml %sp@+,%d0-%d7/%a0-%a6 + rte + "); + +void watch_dog_init(void) { + set_vector(_catchWDint, WD_ISR_LEVEL+24, 0); +} diff --git a/c/src/lib/libbsp/m68k/efi68k/startup/linkcmds b/c/src/lib/libbsp/m68k/efi68k/startup/linkcmds new file mode 100644 index 0000000000..f34bafab92 --- /dev/null +++ b/c/src/lib/libbsp/m68k/efi68k/startup/linkcmds @@ -0,0 +1,108 @@ +/* linkcmds + * + * $Id$ + */ + +OUTPUT_ARCH(m68k) +__DYNAMIC = 0; + +/* + * The memory map looks like this: + * +--------------------+ <- low memory + * | .text | + * | etext | + * | ctor list | the ctor and dtor lists are for + * | dtor list | C++ support + * | _endtext | + * +--------------------+ + * | .data | initialized data goes here + * | _sdata | + * | _edata | + * +--------------------+ + * | .bss | + * | __bss_start | start of bss, cleared by crt0 + * | _end | start of heap, used by sbrk() + * +--------------------+ + * | heap space | + * | _ENDHEAP | + * | stack space | + * | __stack | top of stack + * +--------------------+ <- high memory + */ + + +/* + * User modifiable values: + * + * _VBR location of VBR table + */ + +MEMORY +{ + ram : ORIGIN = 0x203000, LENGTH = 256K +} + +_VBR = 0x200000; /* location of the VBR table (in RAM) */ +_copy_data_from_rom = 0; + +/* + * stick everything in ram (of course) + */ +SECTIONS +{ + .text : + { + CREATE_OBJECT_SYMBOLS + text_start = .; + _text_start = .; + *(.text) + etext = ALIGN(0x10); + _etext = .; + __CTOR_LIST__ = .; + LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) + *(.ctors) + LONG(0) + __CTOR_END__ = .; + __DTOR_LIST__ = .; + LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) + *(.dtors) + LONG(0) + __DTOR_END__ = .; + *(.lit) + *(.shdata) + _endtext = .; + } > ram + .data : + { + data_start = .; + _data_start = .; + _sdata = . ; + *(.data) + CONSTRUCTORS + edata = ALIGN(0x10); + _edata = .; + } > ram + .shbss : + { + *(.shbss) + } > ram + .bss : + { + __bss_start = ALIGN(0x8); + bss_start = .; + _bss_start = .; + *(.bss) + *(COMMON) + end = .; + _end = ALIGN(0x8); + __end = ALIGN(0x8); + } > ram + .stab . (NOLOAD) : + { + [ .stab ] + } + .stabstr . (NOLOAD) : + { + [ .stabstr ] + } +} diff --git a/c/src/lib/libbsp/m68k/efi68k/startup/m68k-stub.c b/c/src/lib/libbsp/m68k/efi68k/startup/m68k-stub.c new file mode 100644 index 0000000000..a37cd2dc83 --- /dev/null +++ b/c/src/lib/libbsp/m68k/efi68k/startup/m68k-stub.c @@ -0,0 +1,782 @@ +/* m68k-stub.c + * + * $Id$ + */ + +#include <efi68k.h> +#include <rtems.h> + +m68k_isr_entry set_vector( + rtems_isr_entry handler, + rtems_vector_number vector, + int type +); + + +void (*exceptionHook)() = 0; + +void outbyte(char c); +char putDebugChar( char c) +{ + outbyte(c); + return c; +} + +char inbyte(void); +char getDebugChar(void) +{ + return inbyte(); +} + +void flush_i_cache(void) +{ + return; +} + +void *memset(void *p, int c, int n) +{ + register int i; + void *s=p; + + for (i=0;i<n;i++) *((char *)p)++=(char)c; + return s; +} + +char *db_strcpy(char *s, const char *t) +{ + char *save=s; + while((*s++ = *t++) != '\0'); + return save; +} + +int db_strlen(const char *s) +{ + int n; + + for (n=0; *s!='\0'; s++) n++; + return n; +} + +/************************************************************************ + * + * external low-level support routines + */ +typedef void (*ExceptionHook)(int); /* pointer to function with int parm */ +typedef void (*Function)(); /* pointer to a function */ + +/* extern Function exceptionHandler(); */ /* assign an exception handler */ +extern ExceptionHook exceptionHook; /* hook variable for errors/exceptions */ +/* extern void exceptionHandler(int vect, void (*function)()); */ + +/************************/ +/* FORWARD DECLARATIONS */ +/************************/ +static void initializeRemcomErrorFrame(); + +/************************************************************************/ +/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ +/* at least NUMREGBYTES*2 are needed for register packets */ +#define BUFMAX 400 + +static char initialized; /* boolean flag. != 0 means we've been initialized */ + +int remote_debug; +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ + +static const char hexchars[]="0123456789abcdef"; + +/* there are 180 bytes of registers on a 68020 w/68881 */ +/* many of the fpa registers are 12 byte (96 bit) registers */ +#define NUMREGBYTES 180 +enum regnames {D0,D1,D2,D3,D4,D5,D6,D7, + A0,A1,A2,A3,A4,A5,A6,A7, + PS,PC, + FP0,FP1,FP2,FP3,FP4,FP5,FP6,FP7, + FPCONTROL,FPSTATUS,FPIADDR + }; + + + +typedef struct FrameStruct +{ + struct FrameStruct *previous; + int exceptionPC; /* pc value when this frame created */ + int exceptionVector; /* cpu vector causing exception */ + short frameSize; /* size of cpu frame in words */ + short sr; /* for 68000, this not always sr */ + int pc; + short format; + int fsaveHeader; + int morejunk[0]; /* exception frame, fp save... */ +} Frame; + +#define FRAMESIZE 10 +int gdbFrameStack[FRAMESIZE]; +static Frame *lastFrame; + +/* + * these should not be static cuz they can be used outside this module + */ +int registers[NUMREGBYTES/4]; +int superStack; + +#define STACKSIZE 600 +int remcomStack[STACKSIZE/sizeof(int)]; +static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1]; + +static ExceptionHook oldExceptionHook; + +#define SAVE_FP_REGS() +#define RESTORE_FP_REGS() + +void return_to_super(); +void return_to_user(); + +asm(" +.text +.align 2 +.globl return_to_super +return_to_super: + oriw #0x0700,%sr + movel registers+60,%sp /* get new stack pointer */ + movel lastFrame,%a0 /* get last frame info */ + bra return_to_any + +.globl return_to_user +return_to_user: + oriw #0x0700,%sr + movel registers+60,%a0 /* get usp */ + movel %a0,%usp /* set usp */ + movel superStack,%sp /* get original stack pointer */ + +return_to_any: + movel lastFrame,%a0 /* get last frame info */ + movel %a0@+,lastFrame /* link in previous frame */ + addql #8,%a0 /* skip over pc, vector#*/ + movew %a0@+,%d0 /* get # of words in cpu frame */ + addw %d0,%a0 /* point to end of data */ + addw %d0,%a0 /* point to end of data */ + movel %a0,%a1 +# +# copy the stack frame + subql #1,%d0 +copyUserLoop: + movew %a1@-,%sp@- + dbf %d0,copyUserLoop +"); + RESTORE_FP_REGS() + asm(" moveml registers,%d0-%d7/%a0-%a6"); + asm(" rte"); /* pop and go! */ + +#define DISABLE_INTERRUPTS() asm(" oriw #0x0700,%sr"); +#define BREAKPOINT() asm(" trap #1"); + +/* this function is called immediately when a level 7 interrupt occurs */ +/* if the previous interrupt level was 7 then we're already servicing */ +/* this interrupt and an rte is in order to return to the debugger. */ +/* For the 68000, the offset for sr is 6 due to the jsr return address */ +asm(" +.text +.align 2 +.globl _debug_level7 +_debug_level7: + movew %d0,%sp@-"); +asm(" movew %sp@(6),%d0"); + +asm(" andiw #0x700,%d0 + cmpiw #0x700,%d0 + beq already7 + movew %sp@+,%d0 + bra _catchException +already7: + movew %sp@+,%d0"); +asm(" lea %sp@(4),%sp"); /* pull off 68000 return address */ + +asm(" rte"); + +extern void _catchException (); + +/* This function is called when an exception occurs. It translates the + * return address found on the stack into an exception vector # which + * is then handled by either handle_exception or a system handler. + * _catchException provides a front end for both. + * + * stack on entry: stack on exit: + * Program counter MSWord exception # MSWord + * Program counter LSWord exception # MSWord + * Status Register + * Return Address MSWord + * Return Address LSWord + */ + +asm(" +.text +.align 2 +.globl _catchException +_catchException: +"); +DISABLE_INTERRUPTS(); +asm(" + moveml %d0-%d7/%a0-%a6,registers /* save registers */ + movel lastFrame,%a0 /* last frame pointer */ + + move.b #64,(0x00600001) + move.b (0x00600007),%d0 + andib #-64,%d0 + move.b %d0,(0x00600007) + +"); +SAVE_FP_REGS(); +asm(" + lea registers,%a5 /* get address of registers */ + movel %sp@+,%d2 /* pop return address */ + addq.l #6,%d2 + sub.l #0x200000,%d2 + divs #6,%d2 +/* addl #1530,%d2 */ /* convert return addr to */ +/* divs #6,%d2 */ /* exception number */ + extl %d2 + + moveql #3,%d3 /* assume a three word frame */ + + cmpiw #3,%d2 /* bus error or address error ? */ + bgt normal /* if >3 then normal error */ + movel %sp@+,%a0@- /* copy error info to frame buff*/ + movel %sp@+,%a0@- /* these are never used */ + moveql #7,%d3 /* this is a 7 word frame */ + +normal: + movew %sp@+,%d1 /* pop status register */ + movel %sp@+,%a4 /* pop program counter */ + movew %d1,%a5@(66) /* save sr */ + movel %a4,%a5@(68) /* save pc in _regisers[] */ + movel %a4,%a0@- /* copy pc to frame buffer */ + movew %d1,%a0@- /* copy sr to frame buffer */ + + movel %sp,superStack /* save supervisor sp */ + + andiw #0x2000,%d1 /* were we in supervisor mode ? */ + beq userMode + movel %a7,%a5@(60) /* save a7 */ + bra saveDone +userMode: + movel %usp,%a1 /* save user stack pointer */ + movel %a1,%a5@(60) /* save user stack pointer */ +saveDone: + + movew %d3,%a0@- /* push frame size in words */ + movel %d2,%a0@- /* push vector number */ + movel %a4,%a0@- /* push exception pc */ + +# +# save old frame link and set the new value + movel lastFrame,%a1 /* last frame pointer */ + movel %a1,%a0@- /* save pointer to prev frame */ + movel %a0,lastFrame + + movel %d2,%sp@- /* push exception num */ + movel exceptionHook,%a0 /* get address of handler */ + jbsr %a0@ /* and call it */ + clrl %sp@ /* replace exception num parm with frame ptr*/ + jbsr _returnFromException /* jbsr, but never returns */ +"); + + +/* + * remcomHandler is a front end for handle_exception. It moves the + * stack pointer into an area reserved for debugger use in case the + * breakpoint happened in supervisor mode. + */ +asm("remcomHandler:"); +asm(" addl #4,%sp"); /* pop off return address */ +asm(" movel %sp@+,%d0"); /* get the exception number */ +asm(" movel stackPtr,%sp"); /* move to remcom stack area */ +asm(" movel %d0,%sp@-"); /* push exception onto stack */ +asm(" andiw #0xf8ff,%sr"); +asm(" jbsr handle_exception"); /* this never returns */ +asm(" rts"); /* return */ + +void _returnFromException( Frame *frame ) +{ + /* if no passed in frame, use the last one */ + if (! frame) + { + frame = lastFrame; + frame->frameSize = 4; + frame->format = 0; + frame->fsaveHeader = -1; /* restore regs, but we dont have fsave info*/ + } + + + /* a 68000 cannot use the internal info pushed onto a bus error + * or address error frame when doing an RTE so don't put this info + * onto the stack or the stack will creep every time this happens. + */ + frame->frameSize=3; + + + /* throw away any frames in the list after this frame */ + lastFrame = frame; + + frame->sr = registers[(int) PS]; + frame->pc = registers[(int) PC]; + + if (registers[(int) PS] & 0x2000) + { + /* return to supervisor mode... */ + return_to_super(); + } + else + { /* return to user mode */ + return_to_user(); + } +} + +int hex(ch) +char ch; +{ + if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10); + if ((ch >= '0') && (ch <= '9')) return (ch-'0'); + if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10); + return (-1); +} + + +/* scan for the sequence $<data>#<checksum> */ +void getpacket(buffer) +char * buffer; +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + char ch; + + do { + /* wait around for the start character, ignore all other characters */ + while ((ch = getDebugChar()) != '$'); + checksum = 0; + xmitcsum = -1; + + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) { + ch = getDebugChar(); + if (ch == '#') break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') { + xmitcsum = hex(getDebugChar()) << 4; + xmitcsum += hex(getDebugChar()); + + if (checksum != xmitcsum) putDebugChar('-'); /* failed checksum */ + else { + putDebugChar('+'); /* successful transfer */ + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') { + putDebugChar( buffer[0] ); + putDebugChar( buffer[1] ); + /* remove sequence chars from buffer */ + count = db_strlen(buffer); + for (i=3; i <= count; i++) buffer[i-3] = buffer[i]; + } + } + } + } while (checksum != xmitcsum); + +} + +/* send the packet in buffer. The host get's one chance to read it. + This routine does not wait for a positive acknowledge. */ + + +void putpacket(buffer) +char * buffer; +{ + unsigned char checksum; + int count; + char ch; + + /* $<packet info>#<checksum>. */ + do { + putDebugChar('$'); + checksum = 0; + count = 0; + + while ((ch=buffer[count])) { + if (! putDebugChar(ch)) return; + checksum += ch; + count += 1; + } + + putDebugChar('#'); + putDebugChar(hexchars[checksum >> 4]); + putDebugChar(hexchars[checksum % 16]); + + } while (1 == 0); /* (getDebugChar() != '+'); */ + +} + +char remcomInBuffer[BUFMAX]; +char remcomOutBuffer[BUFMAX]; +static short error; + + +void debug_error(format, parm) +char * format; +char * parm; +{ + return; +} + +/* convert the memory pointed to by mem into hex, placing result in buf */ +/* return a pointer to the last char put in buf (null) */ +char* mem2hex(mem, buf, count) +char* mem; +char* buf; +int count; +{ + int i; + unsigned char ch; + for (i=0;i<count;i++) { + ch = *mem++; + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + return(buf); +} + +/* convert the hex array pointed to by buf into binary to be placed in mem */ +/* return a pointer to the character AFTER the last byte written */ +char* hex2mem(buf, mem, count) +char* buf; +char* mem; +int count; +{ + int i; + unsigned char ch; + for (i=0;i<count;i++) { + ch = hex(*buf++) << 4; + ch = ch + hex(*buf++); + *mem++ = ch; + } + return(mem); +} + +/* this function takes the 68000 exception number and attempts to + translate this number into a unix compatible signal value */ +int computeSignal( exceptionVector ) +int exceptionVector; +{ + int sigval; + switch (exceptionVector) { + case 2 : sigval = 10; break; /* bus error */ + case 3 : sigval = 10; break; /* address error */ + case 4 : sigval = 4; break; /* illegal instruction */ + case 5 : sigval = 8; break; /* zero divide */ + case 6 : sigval = 8; break; /* chk instruction */ + case 7 : sigval = 8; break; /* trapv instruction */ + case 8 : sigval = 11; break; /* privilege violation */ + case 9 : sigval = 5; break; /* trace trap */ + case 10: sigval = 4; break; /* line 1010 emulator */ + case 11: sigval = 4; break; /* line 1111 emulator */ + + /* Coprocessor protocol violation. Using a standard MMU or FPU + this cannot be triggered by software. Call it a SIGBUS. */ + case 13: sigval = 10; break; + + case 31: sigval = 2; break; /* interrupt */ + case 33: sigval = 5; break; /* breakpoint */ + + /* This is a trap #8 instruction. Apparently it is someone's software + convention for some sort of SIGFPE condition. Whose? How many + people are being screwed by having this code the way it is? + Is there a clean solution? */ + case 40: sigval = 8; break; /* floating point err */ + + case 48: sigval = 8; break; /* floating point err */ + case 49: sigval = 8; break; /* floating point err */ + case 50: sigval = 8; break; /* zero divide */ + case 51: sigval = 8; break; /* underflow */ + case 52: sigval = 8; break; /* operand error */ + case 53: sigval = 8; break; /* overflow */ + case 54: sigval = 8; break; /* NAN */ + default: + sigval = 7; /* "software generated"*/ + } + return (sigval); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +int hexToInt(char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + + while (**ptr) + { + hexValue = hex(**ptr); + if (hexValue >=0) + { + *intValue = (*intValue <<4) | hexValue; + numChars ++; + } + else + break; + + (*ptr)++; + } + + return (numChars); +} + +/* + * This function does all command procesing for interfacing to gdb. + */ +void handle_exception(int exceptionVector) +{ + int sigval; + int addr, length; + char * ptr; + int newPC; + Frame *frame; + + /* reply to host that an exception has occurred */ + sigval = computeSignal( exceptionVector ); + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + + putpacket(remcomOutBuffer); + + while (1==1) { + error = 0; + remcomOutBuffer[0] = 0; + getpacket(remcomInBuffer); + switch (remcomInBuffer[0]) { + case '?' : remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd' : remote_debug = !(remote_debug); /* toggle debug flag */ + break; + case 'g' : /* return the value of the CPU registers */ + mem2hex((char*) registers, remcomOutBuffer, NUMREGBYTES); + break; + case 'G' : /* set the value of the CPU registers - return OK */ + hex2mem(&remcomInBuffer[1], (char*) registers, NUMREGBYTES); + db_strcpy(remcomOutBuffer,"OK"); + break; + + /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + case 'm' : + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr,&addr)) + if (*(ptr++) == ',') + if (hexToInt(&ptr,&length)) + { + ptr = 0; + mem2hex((char*) addr, remcomOutBuffer, length); + } + + if (ptr) + { + db_strcpy(remcomOutBuffer,"E01"); + debug_error("malformed read memory command: %s",remcomInBuffer); + } + break; + + /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + case 'M' : + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr,&addr)) + if (*(ptr++) == ',') + if (hexToInt(&ptr,&length)) + if (*(ptr++) == ':') + { + hex2mem(ptr, (char*) addr, length); + ptr = 0; + db_strcpy(remcomOutBuffer,"OK"); + } + if (ptr) + { + db_strcpy(remcomOutBuffer,"E02"); + debug_error("malformed write memory command: %s",remcomInBuffer); + } + break; + + /* cAA..AA Continue at address AA..AA(optional) */ + /* sAA..AA Step one instruction from AA..AA(optional) */ + case 'c' : + case 's' : + /* try to read optional parameter, pc unchanged if no parm */ + ptr = &remcomInBuffer[1]; + if (hexToInt(&ptr,&addr)) + registers[ PC ] = addr; + + newPC = registers[ PC]; + + /* clear the trace bit */ + registers[ PS ] &= 0x7fff; + + /* set the trace bit if we're stepping */ + if (remcomInBuffer[0] == 's') registers[ PS ] |= 0x8000; + + /* + * look for newPC in the linked list of exception frames. + * if it is found, use the old frame it. otherwise, + * fake up a dummy frame in returnFromException(). + */ + frame = lastFrame; + while (frame) + { + if (frame->exceptionPC == newPC) break; /* bingo! a match */ + /* + * for a breakpoint instruction, the saved pc may + * be off by two due to re-executing the instruction + * replaced by the trap instruction. Check for this. + */ + if ((frame->exceptionVector == 33) && + (frame->exceptionPC == (newPC+2))) break; + if (frame == frame->previous) + { + frame = 0; /* no match found */ + break; + } + frame = frame->previous; + } + + /* + * If we found a match for the PC AND we are not returning + * as a result of a breakpoint (33), + * trace exception (9), nmi (31), jmp to + * the old exception handler as if this code never ran. + */ + if (frame) + { + if ((frame->exceptionVector != 9) && + (frame->exceptionVector != 31) && + (frame->exceptionVector != 33)) + { + /* + * invoke the previous handler. + */ + if (oldExceptionHook) + (*oldExceptionHook) (frame->exceptionVector); + newPC = registers[ PC ]; /* pc may have changed */ + if (newPC != frame->exceptionPC) + { + /* re-use the last frame, we're skipping it (longjump?)*/ + frame = (Frame *) 0; + _returnFromException( frame ); /* this is a jump */ + } + } + } + + /* if we couldn't find a frame, create one */ + if (frame == 0) + { + frame = lastFrame -1 ; + + /* by using a bunch of print commands with breakpoints, + it's possible for the frame stack to creep down. If it creeps + too far, give up and reset it to the top. Normal use should + not see this happen. + */ + if ((unsigned int) (frame-2) < (unsigned int) &gdbFrameStack) + { + initializeRemcomErrorFrame(); + frame = lastFrame; + } + frame->previous = lastFrame; + lastFrame = frame; + frame = 0; /* null so _return... will properly initialize it */ + } + + _returnFromException( frame ); /* this is a jump */ + + break; + + /* kill the program */ + case 'k' : /* do nothing */ + break; + } /* switch */ + + /* reply to the request */ + putpacket(remcomOutBuffer); + } +} + + +void +initializeRemcomErrorFrame() +{ + lastFrame = ((Frame *) &gdbFrameStack[FRAMESIZE-1]) - 1; + lastFrame->previous = lastFrame; +} + +/* this function is used to set up exception handlers for tracing and + breakpoints */ +void set_debug_traps() +{ + extern void _debug_level7(); + extern void remcomHandler(); + int exception; + + initializeRemcomErrorFrame(); + stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1]; + + for (exception = 2; exception <= 23; exception++) + set_vector(_catchException,exception,0); + + /* level 7 interrupt */ + set_vector(_debug_level7,31,0); + + /* breakpoint exception (trap #1) */ + set_vector(_catchException,33,0); + + /* This is a trap #8 instruction. Apparently it is someone's software + convention for some sort of SIGFPE condition. Whose? How many + people are being screwed by having this code the way it is? + Is there a clean solution? */ + set_vector(_catchException,40,0); + + /* 48 to 54 are floating point coprocessor errors */ + for (exception = 48; exception <= 54; exception++) + set_vector(_catchException,exception,0); + + if (oldExceptionHook != remcomHandler) + { + oldExceptionHook = exceptionHook; + exceptionHook = remcomHandler; + } + + initialized = 1; + +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +void breakpoint() +{ + if (initialized) BREAKPOINT(); +} + diff --git a/c/src/lib/libbsp/m68k/efi68k/startup/setvec.c b/c/src/lib/libbsp/m68k/efi68k/startup/setvec.c new file mode 100644 index 0000000000..39eb7a1fa1 --- /dev/null +++ b/c/src/lib/libbsp/m68k/efi68k/startup/setvec.c @@ -0,0 +1,45 @@ +/* set_vector + * + * This routine installs an interrupt vector on the efi68k. + * + * INPUT: + * handler - interrupt handler entry point + * vector - vector number + * type - 0 indicates raw hardware connect + * 1 indicates RTEMS interrupt connect + * + * RETURNS: + * address of previous interrupt handler + * + * COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994. + * On-Line Applications Research Corporation (OAR). + * All rights assigned to U.S. Government, 1994. + * + * This material may be reproduced by or for the U.S. Government pursuant + * to the copyright license under the clause at DFARS 252.227-7013. This + * notice must appear in all copies of this file and its derivatives. + * + * $Id$ + */ + +#include <bsp.h> + +m68k_isr_entry set_vector( /* returns old vector */ + rtems_isr_entry handler, /* isr routine */ + rtems_vector_number vector, /* vector number */ + int type /* RTEMS or RAW intr */ +) +{ + int *p; + m68k_isr_entry previous_isr; + + if ( type ) + rtems_interrupt_catch( handler, vector, (rtems_isr_entry *) &previous_isr ); + else { + p = (int *)(vector*6-12+2+(int)_VBR); + previous_isr = (m68k_isr_entry) *p; /* return old ISR */ + *p = (int) handler; /* install new ISR */ + } + return previous_isr; +} + |