summaryrefslogtreecommitdiffstats
path: root/c/src/exec/score/cpu/sparc
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/exec/score/cpu/sparc')
-rw-r--r--c/src/exec/score/cpu/sparc/README118
-rw-r--r--c/src/exec/score/cpu/sparc/asm.h16
-rw-r--r--c/src/exec/score/cpu/sparc/cpu.c370
-rw-r--r--c/src/exec/score/cpu/sparc/cpu.h674
-rw-r--r--c/src/exec/score/cpu/sparc/cpu_asm.s881
-rw-r--r--c/src/exec/score/cpu/sparc/erc32.h503
-rw-r--r--c/src/exec/score/cpu/sparc/rtems.s16
-rw-r--r--c/src/exec/score/cpu/sparc/sparc.h150
-rw-r--r--c/src/exec/score/cpu/sparc/sparctypes.h26
9 files changed, 2014 insertions, 740 deletions
diff --git a/c/src/exec/score/cpu/sparc/README b/c/src/exec/score/cpu/sparc/README
new file mode 100644
index 0000000000..0c481d67c1
--- /dev/null
+++ b/c/src/exec/score/cpu/sparc/README
@@ -0,0 +1,118 @@
+#
+# $Id$
+#
+
+This file discusses SPARC specific issues which are important to
+this port. The primary topics in this file are:
+
+ + Global Register Usage
+ + Stack Frame
+ + EF bit in the PSR
+
+
+Global Register Usage
+=====================
+
+This information on register usage is based heavily on a comment in the
+file gcc-2.7.0/config/sparc/sparc.h in the the gcc 2.7.0 source.
+
+ + g0 is hardwired to 0
+ + On non-v9 systems:
+ - g1 is free to use as temporary.
+ - g2-g4 are reserved for applications. Gcc normally uses them as
+ temporaries, but this can be disabled via the -mno-app-regs option.
+ - g5 through g7 are reserved for the operating system.
+ + On v9 systems:
+ - g1 and g5 are free to use as temporaries.
+ - g2-g4 are reserved for applications (the compiler will not normally use
+ them, but they can be used as temporaries with -mapp-regs).
+ - g6-g7 are reserved for the operating system.
+
+ NOTE: As of gcc 2.7.0 register g1 was used in the following scenarios:
+
+ + as a temporary by the 64 bit sethi pattern
+ + when restoring call-preserved registers in large stack frames
+
+RTEMS places no constraints on the usage of the global registers. Although
+gcc assumes that either g5-g7 (non-V9) or g6-g7 (V9) are reserved for the
+operating system, RTEMS does not assume any special use for them.
+
+
+
+Stack Frame
+===========
+
+The stack grows downward (i.e. to lower addresses) on the SPARC architecture.
+
+The following is the organization of the stack frame:
+
+
+
+ | ............... |
+ fp | |
+ +-------------------------------+
+ | |
+ | Local registers, temporaries, |
+ | and saved floats | x bytes
+ | |
+ sp + x +-------------------------------+
+ | |
+ | outgoing parameters past |
+ | the sixth one | x bytes
+ | |
+ sp + 92 +-------------------------------+ *
+ | | *
+ | area for callee to save | *
+ | register arguments | * 24 bytes
+ | | *
+ sp + 68 +-------------------------------+ *
+ | | *
+ | structure return pointer | * 4 bytes
+ | | *
+ sp + 64 +-------------------------------+ *
+ | | *
+ | local register set | * 32 bytes
+ | | *
+ sp + 32 +-------------------------------+ *
+ | | *
+ | input register set | * 32 bytes
+ | | *
+ sp +-------------------------------+ *
+
+
+* = minimal stack frame
+
+x = optional components
+
+EF bit in the PSR
+=================
+
+The EF (enable floating point unit) in the PSR is utilized in this port to
+prevent non-floating point tasks from performing floating point
+operations. This bit is maintained as part of the integer context.
+However, the floating point context is switched BEFORE the integer
+context. Thus the EF bit in place at the time of the FP switch may
+indicate that FP operations are disabled. This occurs on certain task
+switches, when the EF bit will be 0 for the outgoing task and thus a fault
+will be generated on the first FP operation of the FP context save.
+
+The remedy for this is to enable FP access as the first step in both the
+save and restore of the FP context area. This bit will be subsequently
+reloaded by the integer context switch.
+
+Two of the scenarios which demonstrate this problem are outlined below:
+
+1. When the first FP task is switched to. The system tasks are not FP and
+thus would be unable to restore the FP context of the incoming task.
+
+2. On a deferred FP context switch. In this case, the system might switch
+from FP Task A to non-FP Task B and then to FP Task C. In this scenario,
+the floating point state must technically be saved by a non-FP task.
+
+
+
+
+
+
+
+
diff --git a/c/src/exec/score/cpu/sparc/asm.h b/c/src/exec/score/cpu/sparc/asm.h
index 10157171c5..a3d62416b8 100644
--- a/c/src/exec/score/cpu/sparc/asm.h
+++ b/c/src/exec/score/cpu/sparc/asm.h
@@ -28,7 +28,9 @@
*/
#define ASM
+
#include <rtems/score/sparc.h>
+#include <rtems/score/cpu.h>
/*
* Recent versions of GNU cpp define variables which indicate the
@@ -37,7 +39,9 @@
* have to define these as appropriate.
*/
-/* XXX This does not appear to work on gcc 2.7.0 on the sparc */
+/* XXX __USER_LABEL_PREFIX__ and __REGISTER_PREFIX__ do not work on gcc 2.7.0 */
+/* XXX The following ifdef magic fixes the problem but results in a warning */
+/* XXX when compiling assembly code. */
#undef __USER_LABEL_PREFIX__
#ifndef __USER_LABEL_PREFIX__
#define __USER_LABEL_PREFIX__ _
@@ -91,6 +95,16 @@
#define PUBLIC(sym) .globl SYM (sym)
#define EXTERN(sym) .globl SYM (sym)
+/*
+ * Entry for traps which jump to a programmer-specified trap handler.
+ */
+
+#define TRAP(_vector, _handler) \
+ mov %psr, %l0 ; \
+ sethi %hi(_handler), %l4 ; \
+ jmp %l4+%lo(_handler); \
+ mov _vector, %l3
+
#endif
/* end of include file */
diff --git a/c/src/exec/score/cpu/sparc/cpu.c b/c/src/exec/score/cpu/sparc/cpu.c
index cf70913d5e..23d998cab5 100644
--- a/c/src/exec/score/cpu/sparc/cpu.c
+++ b/c/src/exec/score/cpu/sparc/cpu.c
@@ -7,52 +7,115 @@
#include <rtems/system.h>
#include <rtems/score/isr.h>
-/* _CPU_Initialize
+#if defined(erc32)
+#include <erc32.h>
+#endif
+
+/*
+ * This initializes the set of opcodes placed in each trap
+ * table entry. The routine which installs a handler is responsible
+ * for filling in the fields for the _handler address and the _vector
+ * trap type.
+ *
+ * The constants following this structure are masks for the fields which
+ * must be filled in when the handler is installed.
+ */
+
+const CPU_Trap_table_entry _CPU_Trap_slot_template = {
+ 0xa1480000, /* mov %psr, %l0 */
+ 0x29000000, /* sethi %hi(_handler), %l4 */
+ 0x81c52000, /* jmp %l4 + %lo(_handler) */
+ 0xa6102000 /* mov _vector, %l3 */
+};
+
+/*PAGE
+ *
+ * _CPU_Initialize
*
* This routine performs processor dependent initialization.
*
- * INPUT PARAMETERS:
+ * Input Parameters:
* cpu_table - CPU table to initialize
* thread_dispatch - address of disptaching routine
+ *
+ * Output Parameters: NONE
+ *
+ * NOTE: There is no need to save the pointer to the thread dispatch routine.
+ * The SPARC's assembly code can reference it directly with no problems.
*/
-
void _CPU_Initialize(
rtems_cpu_table *cpu_table,
- void (*thread_dispatch) /* ignored on this CPU */
+ void (*thread_dispatch) /* ignored on this CPU */
)
{
- void *pointer;
+ void *pointer;
+ unsigned32 trap_table_start;
+ unsigned32 tbr_value;
+ CPU_Trap_table_entry *old_tbr;
+ CPU_Trap_table_entry *trap_table;
/*
- * The thread_dispatch argument is the address of the entry point
- * for the routine called at the end of an ISR once it has been
- * decided a context switch is necessary. On some compilation
- * systems it is difficult to call a high-level language routine
- * from assembly. This allows us to trick these systems.
- *
- * If you encounter this problem save the entry point in a CPU
- * dependent variable.
+ * Install the executive's trap table. All entries from the original
+ * trap table are copied into the executive's trap table. This is essential
+ * since this preserves critical trap handlers such as the window underflow
+ * and overflow handlers. It is the responsibility of the BSP to provide
+ * install these in the initial trap table.
*/
+
+ trap_table_start = (unsigned32) &_CPU_Trap_Table_area;
+ if (trap_table_start & (SPARC_TRAP_TABLE_ALIGNMENT-1))
+ trap_table_start = (trap_table_start + SPARC_TRAP_TABLE_ALIGNMENT) &
+ ~(SPARC_TRAP_TABLE_ALIGNMENT-1);
+
+ trap_table = (CPU_Trap_table_entry *) trap_table_start;
+
+ sparc_get_tbr( tbr_value );
- _CPU_Thread_dispatch_pointer = thread_dispatch;
+ old_tbr = (CPU_Trap_table_entry *) (tbr_value & 0xfffff000);
+
+ memcpy( trap_table, (void *) old_tbr, 256 * sizeof( CPU_Trap_table_entry ) );
+
+ sparc_set_tbr( trap_table_start );
/*
- * If there is not an easy way to initialize the FP context
- * during Context_Initialize, then it is usually easier to
- * save an "uninitialized" FP context here and copy it to
- * the task's during Context_Initialize.
+ * This seems to be the most appropriate way to obtain an initial
+ * FP context on the SPARC. The NULL fp context is copied it to
+ * the task's FP context during Context_Initialize.
*/
pointer = &_CPU_Null_fp_context;
_CPU_Context_save_fp( &pointer );
+ /*
+ * Grab our own copy of the user's CPU table.
+ */
+
_CPU_Table = *cpu_table;
+
+#if defined(erc32)
+
+ /*
+ * ERC32 specific initialization
+ */
+
+ _ERC32_MEC_Timer_Control_Mirror = 0;
+ ERC32_MEC.Timer_Control = 0;
+
+ ERC32_MEC.Control |= ERC32_CONFIGURATION_POWER_DOWN_ALLOWED;
+
+#endif
+
}
/*PAGE
*
* _CPU_ISR_Get_level
+ *
+ * Input Parameters: NONE
+ *
+ * Output Parameters:
+ * returns the current interrupt level (PIL field of the PSR)
*/
unsigned32 _CPU_ISR_Get_level( void )
@@ -64,134 +127,263 @@ unsigned32 _CPU_ISR_Get_level( void )
return level;
}
-/* _CPU_ISR_install_vector
+/*PAGE
+ *
+ * _CPU_ISR_install_raw_handler
+ *
+ * This routine installs the specified handler as a "raw" non-executive
+ * supported trap handler (a.k.a. interrupt service routine).
+ *
+ * Input Parameters:
+ * vector - trap table entry number plus synchronous
+ * vs. asynchronous information
+ * new_handler - address of the handler to be installed
+ * old_handler - pointer to an address of the handler previously installed
+ *
+ * Output Parameters: NONE
+ * *new_handler - address of the handler previously installed
+ *
+ * NOTE:
+ *
+ * On the SPARC, there are really only 256 vectors. However, the executive
+ * has no easy, fast, reliable way to determine which traps are synchronous
+ * and which are asynchronous. By default, synchronous traps return to the
+ * instruction which caused the interrupt. So if you install a software
+ * trap handler as an executive interrupt handler (which is desirable since
+ * RTEMS takes care of window and register issues), then the executive needs
+ * to know that the return address is to the trap rather than the instruction
+ * following the trap.
+ *
+ * So vectors 0 through 255 are treated as regular asynchronous traps which
+ * provide the "correct" return address. Vectors 256 through 512 are assumed
+ * by the executive to be synchronous and to require that the return address
+ * be fudged.
+ *
+ * If you use this mechanism to install a trap handler which must reexecute
+ * the instruction which caused the trap, then it should be installed as
+ * an asynchronous trap. This will avoid the executive changing the return
+ * address.
+ */
+
+void _CPU_ISR_install_raw_handler(
+ unsigned32 vector,
+ proc_ptr new_handler,
+ proc_ptr *old_handler
+)
+{
+ unsigned32 real_vector;
+ CPU_Trap_table_entry *tbr;
+ CPU_Trap_table_entry *slot;
+ unsigned32 u32_tbr;
+ unsigned32 u32_handler;
+
+ /*
+ * Get the "real" trap number for this vector ignoring the synchronous
+ * versus asynchronous indicator included with our vector numbers.
+ */
+
+ real_vector = SPARC_REAL_TRAP_NUMBER( vector );
+
+ /*
+ * Get the current base address of the trap table and calculate a pointer
+ * to the slot we are interested in.
+ */
+
+ sparc_get_tbr( u32_tbr );
+
+ u32_tbr &= 0xfffff000;
+
+ tbr = (CPU_Trap_table_entry *) u32_tbr;
+
+ slot = &tbr[ real_vector ];
+
+ /*
+ * Get the address of the old_handler from the trap table.
+ *
+ * NOTE: The old_handler returned will be bogus if it does not follow
+ * the RTEMS model.
+ */
+
+#define HIGH_BITS_MASK 0xFFFFFC00
+#define HIGH_BITS_SHIFT 10
+#define LOW_BITS_MASK 0x000003FF
+
+ if ( slot->mov_psr_l0 == _CPU_Trap_slot_template.mov_psr_l0 ) {
+ u32_handler =
+ ((slot->sethi_of_handler_to_l4 & HIGH_BITS_MASK) << HIGH_BITS_SHIFT) |
+ (slot->jmp_to_low_of_handler_plus_l4 & LOW_BITS_MASK);
+ *old_handler = (proc_ptr) u32_handler;
+ } else
+ *old_handler = 0;
+
+ /*
+ * Copy the template to the slot and then fix it.
+ */
+
+ *slot = _CPU_Trap_slot_template;
+
+ u32_handler = (unsigned32) new_handler;
+
+ slot->mov_vector_l3 |= vector;
+ slot->sethi_of_handler_to_l4 |=
+ (u32_handler & HIGH_BITS_MASK) >> HIGH_BITS_SHIFT;
+ slot->jmp_to_low_of_handler_plus_l4 |= (u32_handler & LOW_BITS_MASK);
+}
+
+/*PAGE
+ *
+ * _CPU_ISR_install_vector
*
* This kernel routine installs the RTEMS handler for the
* specified vector.
*
* Input parameters:
- * vector - interrupt vector number
- * old_handler - former ISR for this vector number
- * new_handler - replacement ISR for this vector number
+ * vector - interrupt vector number
+ * new_handler - replacement ISR for this vector number
+ * old_handler - pointer to former ISR for this vector number
*
- * Output parameters: NONE
+ * Output parameters:
+ * *old_handler - former ISR for this vector number
*
*/
-
void _CPU_ISR_install_vector(
unsigned32 vector,
proc_ptr new_handler,
proc_ptr *old_handler
)
{
- *old_handler = _ISR_Vector_table[ vector ];
+ unsigned32 real_vector;
+ proc_ptr ignored;
+
+ /*
+ * Get the "real" trap number for this vector ignoring the synchronous
+ * versus asynchronous indicator included with our vector numbers.
+ */
+
+ real_vector = SPARC_REAL_TRAP_NUMBER( vector );
/*
- * If the interrupt vector table is a table of pointer to isr entry
- * points, then we need to install the appropriate RTEMS interrupt
- * handler for this vector number.
+ * Return the previous ISR handler.
*/
+ *old_handler = _ISR_Vector_table[ real_vector ];
+
/*
- * We put the actual user ISR address in '_ISR_vector_table'. This will
- * be used by the _ISR_Handler so the user gets control.
+ * Install the wrapper so this ISR can be invoked properly.
*/
- _ISR_Vector_table[ vector ] = new_handler;
-}
+ _CPU_ISR_install_raw_handler( vector, _ISR_Handler, &ignored );
-/*PAGE
- *
- * _CPU_Install_interrupt_stack
- */
+ /*
+ * We put the actual user ISR address in '_ISR_vector_table'. This will
+ * be used by the _ISR_Handler so the user gets control.
+ */
-void _CPU_Install_interrupt_stack( void )
-{
+ _ISR_Vector_table[ real_vector ] = new_handler;
}
/*PAGE
*
* _CPU_Context_Initialize
+ *
+ * This kernel routine initializes the basic non-FP context area associated
+ * with each thread.
+ *
+ * Input parameters:
+ * the_context - pointer to the context area
+ * stack_base - address of memory for the SPARC
+ * size - size in bytes of the stack area
+ * new_level - interrupt level for this context area
+ * entry_point - the starting execution point for this this context
+ * is_fp - TRUE if this context is associated with an FP thread
+ *
+ * Output parameters: NONE
*/
-/*
- * The following constants assist in building a thread's initial context.
- */
-
-#define CPU_FRAME_SIZE (112) /* based on disassembled test code */
-#define ADDR_ADJ_OFFSET -8
-
void _CPU_Context_Initialize(
- Context_Control *_the_context,
- unsigned32 *_stack_base,
- unsigned32 _size,
- unsigned32 _new_level,
- void *_entry_point
+ Context_Control *the_context,
+ unsigned32 *stack_base,
+ unsigned32 size,
+ unsigned32 new_level,
+ void *entry_point,
+ boolean is_fp
)
{
- unsigned32 jmp_addr;
- unsigned32 _stack_high; /* highest "stack aligned" address */
- unsigned32 _the_size;
+ unsigned32 stack_high; /* highest "stack aligned" address */
+ unsigned32 the_size;
unsigned32 tmp_psr;
- jmp_addr = (unsigned32) _entry_point;
-
/*
* On CPUs with stacks which grow down (i.e. SPARC), we build the stack
- * based on the _stack_high address.
+ * based on the stack_high address.
*/
- _stack_high = ((unsigned32)(_stack_base) + _size);
- _stack_high &= ~(CPU_STACK_ALIGNMENT - 1);
+ stack_high = ((unsigned32)(stack_base) + size);
+ stack_high &= ~(CPU_STACK_ALIGNMENT - 1);
- _the_size = _size & ~(CPU_STACK_ALIGNMENT - 1);
+ the_size = size & ~(CPU_STACK_ALIGNMENT - 1);
-/* XXX following code is based on unix port */
/*
- * XXX SPARC port needs a diagram like this one...
- * See /usr/include/sys/stack.h in Solaris 2.3 for a nice
- * diagram of the stack.
+ * See the README in this directory for a diagram of the stack.
*/
- _the_context->o7 = jmp_addr + ADDR_ADJ_OFFSET;
- _the_context->o6 = (unsigned32)(_stack_high - CPU_FRAME_SIZE);
- _the_context->i6 = (unsigned32)(_stack_high);
-#if 0
- _the_context->rp = jmp_addr + ADDR_ADJ_OFFSET;
- _the_context->sp = (unsigned32)(_stack_high - CPU_FRAME_SIZE);
- _the_context->fp = (unsigned32)(_stack_high);
-#endif
+ the_context->o7 = ((unsigned32) entry_point) - 8;
+ the_context->o6_sp = stack_high - CPU_MINIMUM_STACK_FRAME_SIZE;
+ the_context->i6_fp = stack_high;
- _the_context->wim = 0x01;
+ /*
+ * Build the PSR for the task. Most everything can be 0 and the
+ * CWP is corrected during the context switch.
+ *
+ * The EF bit determines if the floating point unit is available.
+ * The FPU is ONLY enabled if the context is associated with an FP task
+ * and this SPARC model has an FPU.
+ */
sparc_get_psr( tmp_psr );
- tmp_psr &= ~SPARC_PIL_MASK;
- tmp_psr |= (((_new_level) << 8) & SPARC_PIL_MASK);
- tmp_psr = (tmp_psr & ~0x07) | 0x07; /* XXX should use num windows */
- _the_context->psr = tmp_psr;
+ tmp_psr &= ~SPARC_PSR_PIL_MASK;
+ tmp_psr |= (new_level << 8) & SPARC_PSR_PIL_MASK;
+ tmp_psr &= ~SPARC_PSR_EF_MASK; /* disabled by default */
+
+#if (SPARC_HAS_FPU == 1)
+ /*
+ * If this bit is not set, then a task gets a fault when it accesses
+ * a floating point register. This is a nice way to detect floating
+ * point tasks which are not currently declared as such.
+ */
+
+ if ( is_fp )
+ tmp_psr |= SPARC_PSR_EF_MASK;
+#endif
+ the_context->psr = tmp_psr;
}
/*PAGE
*
* _CPU_Internal_threads_Idle_thread_body
*
- * NOTES:
- *
- * 1. This is the same as the regular CPU independent algorithm.
- *
- * 2. If you implement this using a "halt", "idle", or "shutdown"
- * instruction, then don't forget to put it in an infinite loop.
+ * Some SPARC implementations have low power, sleep, or idle modes. This
+ * tries to take advantage of those models.
+ */
+
+#if (CPU_PROVIDES_IDLE_THREAD_BODY == TRUE)
+
+/*
+ * This is the implementation for the erc32.
*
- * 3. Be warned. Some processors with onboard DMA have been known
- * to stop the DMA if the CPU were put in IDLE mode. This might
- * also be a problem with other on-chip peripherals. So use this
- * hook with caution.
+ * NOTE: Low power mode was enabled at initialization time.
*/
+#if defined(erc32)
+
void _CPU_Internal_threads_Idle_thread_body( void )
{
-
- for( ; ; )
- /* insert your "halt" instruction here */ ;
+ while (1) {
+ ERC32_MEC.Power_Down = 0; /* value is irrelevant */
+ }
}
+
+#endif
+
+#endif /* CPU_PROVIDES_IDLE_THREAD_BODY */
diff --git a/c/src/exec/score/cpu/sparc/cpu.h b/c/src/exec/score/cpu/sparc/cpu.h
index 6b9890d132..c631d6a85f 100644
--- a/c/src/exec/score/cpu/sparc/cpu.h
+++ b/c/src/exec/score/cpu/sparc/cpu.h
@@ -1,7 +1,7 @@
/* cpu.h
*
- * This include file contains information pertaining to the XXX
- * processor.
+ * This include file contains information pertaining to the port of
+ * the executive to the SPARC processor.
*
* $Id$
*/
@@ -25,16 +25,6 @@ extern "C" {
*
* If TRUE, then they are inlined.
* If FALSE, then a subroutine call is made.
- *
- * Basically this is an example of the classic trade-off of size
- * versus speed. Inlining the call (TRUE) typically increases the
- * size of the executive while speeding up the enabling of dispatching.
- * [NOTE: In general, the _Thread_Dispatch_disable_level will
- * only be 0 or 1 unless you are in an interrupt handler and that
- * interrupt handler invokes the executive.] When not inlined
- * something calls _Thread_Enable_dispatch which in turns calls
- * _Thread_Dispatch. If the enable dispatch is inlined, then
- * one subroutine call is avoided entirely.]
*/
#define CPU_INLINE_ENABLE_DISPATCH TRUE
@@ -48,13 +38,10 @@ extern "C" {
* If TRUE, then the loops are unrolled.
* If FALSE, then the loops are not unrolled.
*
- * The primary factor in making this decision is the cost of disabling
- * and enabling interrupts (_ISR_Flash) versus the cost of rest of the
- * body of the loop. On some CPUs, the flash is more expensive than
- * one iteration of the loop body. In this case, it might be desirable
- * to unroll the loop. It is important to note that on some CPUs, this
- * code is the longest interrupt disable period in the executive. So it is
- * necessary to strike a balance when setting this parameter.
+ * This parameter could go either way on the SPARC. The interrupt flash
+ * code is relatively lengthy given the requirements for nops following
+ * writes to the psr. But if the clock speed were high enough, this would
+ * not represent a great deal of time.
*/
#define CPU_UNROLL_ENQUEUE_PRIORITY TRUE
@@ -65,25 +52,11 @@ extern "C" {
* If TRUE, then a stack is allocated in _Interrupt_Manager_initialization.
* If FALSE, nothing is done.
*
- * If the CPU supports a dedicated interrupt stack in hardware,
- * then it is generally the responsibility of the BSP to allocate it
- * and set it up.
- *
- * If the CPU does not support a dedicated interrupt stack, then
- * the porter has two options: (1) execute interrupts on the stack of
- * the interrupted task, and (2) have the executive manage a dedicated
- * interrupt stack.
- *
- * If this is TRUE, CPU_ALLOCATE_INTERRUPT_STACK should also be TRUE.
- *
- * Only one of CPU_HAS_SOFTWARE_INTERRUPT_STACK and
- * CPU_HAS_HARDWARE_INTERRUPT_STACK should be set to TRUE. It is
- * possible that both are FALSE for a particular CPU. Although it
- * is unclear what that would imply about the interrupt processing
- * procedure on that CPU.
+ * The SPARC does not have a dedicated HW interrupt stack and one has
+ * been implemented in SW.
*/
-#define CPU_HAS_SOFTWARE_INTERRUPT_STACK FALSE /* XXX */
+#define CPU_HAS_SOFTWARE_INTERRUPT_STACK TRUE
/*
* Does this CPU have hardware support for a dedicated interrupt stack?
@@ -91,25 +64,16 @@ extern "C" {
* If TRUE, then it must be installed during initialization.
* If FALSE, then no installation is performed.
*
- * If this is TRUE, CPU_ALLOCATE_INTERRUPT_STACK should also be TRUE.
- *
- * Only one of CPU_HAS_SOFTWARE_INTERRUPT_STACK and
- * CPU_HAS_HARDWARE_INTERRUPT_STACK should be set to TRUE. It is
- * possible that both are FALSE for a particular CPU. Although it
- * is unclear what that would imply about the interrupt processing
- * procedure on that CPU.
+ * The SPARC does not have a dedicated HW interrupt stack.
*/
-#define CPU_HAS_HARDWARE_INTERRUPT_STACK TRUE /* XXX */
+#define CPU_HAS_HARDWARE_INTERRUPT_STACK FALSE
/*
* Do we allocate a dedicated interrupt stack in the Interrupt Manager?
*
* If TRUE, then the memory is allocated during initialization.
* If FALSE, then the memory is allocated during initialization.
- *
- * This should be TRUE is CPU_HAS_SOFTWARE_INTERRUPT_STACK is TRUE
- * or CPU_INSTALL_HARDWARE_INTERRUPT_STACK is TRUE.
*/
#define CPU_ALLOCATE_INTERRUPT_STACK TRUE
@@ -119,15 +83,6 @@ extern "C" {
*
* If TRUE, then the FLOATING_POINT task attribute is supported.
* If FALSE, then the FLOATING_POINT task attribute is ignored.
- *
- * If there is a FP coprocessor such as the i387 or mc68881, then
- * the answer is TRUE.
- *
- * The macro name "SPARC_HAS_FPU" should be made CPU specific.
- * It indicates whether or not this CPU model has FP support. For
- * example, it would be possible to have an i386_nofp CPU model
- * which set this to false to indicate that you have an i386 without
- * an i387 and wish to leave floating point support out.
*/
#if ( SPARC_HAS_FPU == 1 )
@@ -141,15 +96,6 @@ extern "C" {
*
* If TRUE, then the FLOATING_POINT task attribute is assumed.
* If FALSE, then the FLOATING_POINT task attribute is followed.
- *
- * So far, the only CPU in which this option has been used is the
- * HP PA-RISC. The HP C compiler and gcc both implicitly use the
- * floating point registers to perform integer multiplies. If
- * a function which you would not think utilize the FP unit DOES,
- * then one can not easily predict which tasks will use the FP hardware.
- * In this case, this option should be TRUE.
- *
- * If CPU_HARDWARE_FP is FALSE, then this should be FALSE as well.
*/
#define CPU_ALL_TASKS_ARE_FP FALSE
@@ -160,10 +106,6 @@ extern "C" {
* If TRUE, then the IDLE task is created as a FLOATING_POINT task
* and it has a floating point context which is switched in and out.
* If FALSE, then the IDLE task does not have a floating point context.
- *
- * Setting this to TRUE negatively impacts the time required to preempt
- * the IDLE task from an interrupt because the floating point context
- * must be saved as part of the preemption.
*/
#define CPU_IDLE_TASK_IS_FP FALSE
@@ -181,17 +123,6 @@ extern "C" {
* point task is switched out and restored when the next floating point
* task is restored. The state of the floating point registers between
* those two operations is not specified.
- *
- * If the floating point context does NOT have to be saved as part of
- * interrupt dispatching, then it should be safe to set this to TRUE.
- *
- * Setting this flag to TRUE results in using a different algorithm
- * for deciding when to save and restore the floating point context.
- * The deferred FP switch algorithm minimizes the number of times
- * the FP context is saved and restored. The FP context is not saved
- * until a context switch is made to another, different FP task.
- * Thus in a system with only one FP task, the FP context will never
- * be saved or restored.
*/
#define CPU_USE_DEFERRED_FP_SWITCH TRUE
@@ -205,19 +136,13 @@ extern "C" {
*
* If FALSE, then use the generic IDLE thread body if the BSP does
* not provide one.
- *
- * This is intended to allow for supporting processors which have
- * a low power or idle mode. When the IDLE thread is executed, then
- * the CPU can be powered down.
- *
- * The order of precedence for selecting the IDLE thread body is:
- *
- * 1. BSP provided
- * 2. CPU dependent (if provided)
- * 3. generic (if no BSP and no CPU dependent)
*/
+#if (SPARC_HAS_LOW_POWER_MODE == 1)
+#define CPU_PROVIDES_IDLE_THREAD_BODY TRUE
+#else
#define CPU_PROVIDES_IDLE_THREAD_BODY FALSE
+#endif
/*
* Does the stack grow up (toward higher addresses) or down
@@ -225,6 +150,8 @@ extern "C" {
*
* If TRUE, then the grows upward.
* If FALSE, then the grows toward smaller addresses.
+ *
+ * The stack grows to lower addresses on the SPARC.
*/
#define CPU_STACK_GROWS_UP FALSE
@@ -236,17 +163,8 @@ extern "C" {
* the minimum requirements of the compiler in order to have as
* much of the critical data area as possible in a cache line.
*
- * The placement of this macro in the declaration of the variables
- * is based on the syntactically requirements of the GNU C
- * "__attribute__" extension. For example with GNU C, use
- * the following to force a structures to a 32 byte boundary.
- *
- * __attribute__ ((aligned (32)))
- *
- * NOTE: Currently only the Priority Bit Map table uses this feature.
- * To benefit from using this, the data must be heavily
- * used so it will stay in the cache and used frequently enough
- * in the executive to justify turning this on.
+ * The SPARC does not appear to have particularly strict alignment
+ * requirements. This value was chosen to take advantages of caches.
*/
#define CPU_STRUCTURE_ALIGNMENT __attribute__ ((aligned (16)))
@@ -255,18 +173,80 @@ extern "C" {
* The following defines the number of bits actually used in the
* interrupt field of the task mode. How those bits map to the
* CPU interrupt levels is defined by the routine _CPU_ISR_Set_level().
+ *
+ * The SPARC has 16 interrupt levels in the PIL field of the PSR.
*/
#define CPU_MODES_INTERRUPT_MASK 0x0000000F
/*
- * Processor defined structures
- *
- * Examples structures include the descriptor tables from the i386
- * and the processor control structure on the i960ca.
+ * This structure represents the organization of the minimum stack frame
+ * for the SPARC. More framing information is required in certain situaions
+ * such as when there are a large number of out parameters or when the callee
+ * must save floating point registers.
*/
-/* XXX may need to put some structures here. */
+#ifndef ASM
+
+typedef struct {
+ unsigned32 l0;
+ unsigned32 l1;
+ unsigned32 l2;
+ unsigned32 l3;
+ unsigned32 l4;
+ unsigned32 l5;
+ unsigned32 l6;
+ unsigned32 l7;
+ unsigned32 i0;
+ unsigned32 i1;
+ unsigned32 i2;
+ unsigned32 i3;
+ unsigned32 i4;
+ unsigned32 i5;
+ unsigned32 i6_fp;
+ unsigned32 i7;
+ void *structure_return_address;
+ /*
+ * The following are for the callee to save the register arguments in
+ * should this be necessary.
+ */
+ unsigned32 saved_arg0;
+ unsigned32 saved_arg1;
+ unsigned32 saved_arg2;
+ unsigned32 saved_arg3;
+ unsigned32 saved_arg4;
+ unsigned32 saved_arg5;
+ unsigned32 pad0;
+} CPU_Minimum_stack_frame;
+
+#endif /* ASM */
+
+#define CPU_STACK_FRAME_L0_OFFSET 0x00
+#define CPU_STACK_FRAME_L1_OFFSET 0x04
+#define CPU_STACK_FRAME_L2_OFFSET 0x08
+#define CPU_STACK_FRAME_L3_OFFSET 0x0c
+#define CPU_STACK_FRAME_L4_OFFSET 0x10
+#define CPU_STACK_FRAME_L5_OFFSET 0x14
+#define CPU_STACK_FRAME_L6_OFFSET 0x18
+#define CPU_STACK_FRAME_L7_OFFSET 0x1c
+#define CPU_STACK_FRAME_I0_OFFSET 0x20
+#define CPU_STACK_FRAME_I1_OFFSET 0x24
+#define CPU_STACK_FRAME_I2_OFFSET 0x28
+#define CPU_STACK_FRAME_I3_OFFSET 0x2c
+#define CPU_STACK_FRAME_I4_OFFSET 0x30
+#define CPU_STACK_FRAME_I5_OFFSET 0x34
+#define CPU_STACK_FRAME_I6_FP_OFFSET 0x38
+#define CPU_STACK_FRAME_I7_OFFSET 0x3c
+#define CPU_STRUCTURE_RETURN_ADDRESS_OFFSET 0x40
+#define CPU_STACK_FRAME_SAVED_ARG0_OFFSET 0x44
+#define CPU_STACK_FRAME_SAVED_ARG1_OFFSET 0x48
+#define CPU_STACK_FRAME_SAVED_ARG2_OFFSET 0x4c
+#define CPU_STACK_FRAME_SAVED_ARG3_OFFSET 0x50
+#define CPU_STACK_FRAME_SAVED_ARG4_OFFSET 0x54
+#define CPU_STACK_FRAME_SAVED_ARG5_OFFSET 0x58
+#define CPU_STACK_FRAME_PAD0_OFFSET 0x5c
+
+#define CPU_MINIMUM_STACK_FRAME_SIZE 0x60
/*
* Contexts
@@ -280,35 +260,21 @@ extern "C" {
* 2. floating point task stuff:: Context_Control_fp
* 3. special interrupt level context :: Context_Control_interrupt
*
- * On some processors, it is cost-effective to save only the callee
- * preserved registers during a task context switch. This means
- * that the ISR code needs to save those registers which do not
- * persist across function calls. It is not mandatory to make this
- * distinctions between the caller/callee saves registers for the
- * purpose of minimizing context saved during task switch and on interrupts.
- * If the cost of saving extra registers is minimal, simplicity is the
- * choice. Save the same context on interrupt entry as for tasks in
- * this case.
- *
- * Additionally, if gdb is to be made aware of tasks for this CPU, then
- * care should be used in designing the context area.
- *
- * On some CPUs with hardware floating point support, the Context_Control_fp
- * structure will not be used or it simply consist of an array of a
- * fixed number of bytes. This is done when the floating point context
- * is dumped by a "FP save context" type instruction and the format
- * is not really defined by the CPU. In this case, there is no need
- * to figure out the exact format -- only the size. Of course, although
- * this is enough information for context switches, it is probably not
- * enough for a debugger such as gdb. But that is another problem.
+ * On the SPARC, we are relatively conservative in that we save most
+ * of the CPU state in the context area. The ET (enable trap) bit and
+ * the CWP (current window pointer) fields of the PSR are considered
+ * system wide resources and are not maintained on a per-thread basis.
*/
#ifndef ASM
-/* XXX */
typedef struct {
- unsigned32 g0;
- unsigned32 g1;
+ /*
+ * Using a double g0_g1 will put everything in this structure on a
+ * double word boundary which allows us to use double word loads
+ * and stores safely in the context switch.
+ */
+ double g0_g1;
unsigned32 g2;
unsigned32 g3;
unsigned32 g4;
@@ -331,7 +297,7 @@ typedef struct {
unsigned32 i3;
unsigned32 i4;
unsigned32 i5;
- unsigned32 i6;
+ unsigned32 i6_fp;
unsigned32 i7;
unsigned32 o0;
@@ -340,10 +306,9 @@ typedef struct {
unsigned32 o3;
unsigned32 o4;
unsigned32 o5;
- unsigned32 o6;
+ unsigned32 o6_sp;
unsigned32 o7;
- unsigned32 wim;
unsigned32 psr;
} Context_Control;
@@ -377,7 +342,7 @@ typedef struct {
#define I3_OFFSET 0x4C
#define I4_OFFSET 0x50
#define I5_OFFSET 0x54
-#define I6_OFFSET 0x58
+#define I6_FP_OFFSET 0x58
#define I7_OFFSET 0x5C
#define O0_OFFSET 0x60
@@ -386,15 +351,19 @@ typedef struct {
#define O3_OFFSET 0x6C
#define O4_OFFSET 0x70
#define O5_OFFSET 0x74
-#define O6_OFFSET 0x78
+#define O6_SP_OFFSET 0x78
#define O7_OFFSET 0x7C
-#define WIM_OFFSET 0x80
-#define PSR_OFFSET 0x84
+#define PSR_OFFSET 0x80
+
+#define CONTEXT_CONTROL_SIZE 0x84
+
+/*
+ * The floating point context area.
+ */
#ifndef ASM
-/* XXX */
typedef struct {
double f0_f1;
double f2_f3;
@@ -439,10 +408,39 @@ typedef struct {
#define F3O_F31_OFFSET 0x78
#define FSR_OFFSET 0x80
+#define CONTEXT_CONTROL_FP_SIZE 0x84
+
#ifndef ASM
+/*
+ * Context saved on stack for an interrupt.
+ *
+ * NOTE: The PSR, PC, and NPC are only saved in this structure for the
+ * benefit of the user's handler.
+ */
+
typedef struct {
- unsigned32 special_interrupt_register_XXX;
+ CPU_Minimum_stack_frame Stack_frame;
+ unsigned32 psr;
+ unsigned32 pc;
+ unsigned32 npc;
+ unsigned32 g1;
+ unsigned32 g2;
+ unsigned32 g3;
+ unsigned32 g4;
+ unsigned32 g5;
+ unsigned32 g6;
+ unsigned32 g7;
+ unsigned32 i0;
+ unsigned32 i1;
+ unsigned32 i2;
+ unsigned32 i3;
+ unsigned32 i4;
+ unsigned32 i5;
+ unsigned32 i6_fp;
+ unsigned32 i7;
+ unsigned32 y;
+ unsigned32 pad0_offset;
} CPU_Interrupt_frame;
#endif /* ASM */
@@ -451,11 +449,34 @@ typedef struct {
* Offsets of fields with CPU_Interrupt_frame for assembly routines.
*/
+#define ISF_STACK_FRAME_OFFSET 0x00
+#define ISF_PSR_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x00
+#define ISF_PC_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x04
+#define ISF_NPC_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x08
+#define ISF_G1_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x0c
+#define ISF_G2_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x10
+#define ISF_G3_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x14
+#define ISF_G4_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x18
+#define ISF_G5_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x1c
+#define ISF_G6_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x20
+#define ISF_G7_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x24
+#define ISF_I0_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x28
+#define ISF_I1_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x2c
+#define ISF_I2_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x30
+#define ISF_I3_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x34
+#define ISF_I4_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x38
+#define ISF_I5_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x3c
+#define ISF_I6_FP_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x40
+#define ISF_I7_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x44
+#define ISF_Y_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x48
+#define ISF_PAD0_OFFSET CPU_MINIMUM_STACK_FRAME_SIZE + 0x4c
+
+#define CONTEXT_CONTROL_INTERRUPT_FRAME_SIZE CPU_MINIMUM_STACK_FRAME_SIZE + 0x50
#ifndef ASM
/*
* The following table contains the information required to configure
- * the XXX processor specific parameters.
+ * the processor specific parameters.
*
* NOTE: The interrupt_stack_size field is required if
* CPU_ALLOCATE_INTERRUPT_STACK is defined as TRUE.
@@ -472,61 +493,97 @@ typedef struct {
boolean do_zero_of_workspace;
unsigned32 interrupt_stack_size;
unsigned32 extra_system_initialization_stack;
- unsigned32 some_other_cpu_dependent_info_XXX;
} rtems_cpu_table;
/*
- * This variable is optional. It is used on CPUs on which it is difficult
- * to generate an "uninitialized" FP context. It is filled in by
- * _CPU_Initialize and copied into the task's FP context area during
- * _CPU_Context_Initialize.
+ * This variable is contains the initialize context for the FP unit.
+ * It is filled in by _CPU_Initialize and copied into the task's FP
+ * context area during _CPU_Context_Initialize.
*/
EXTERN Context_Control_fp _CPU_Null_fp_context CPU_STRUCTURE_ALIGNMENT;
/*
- * On some CPUs, software managed interrupt stack is supported.
* This stack is allocated by the Interrupt Manager and the switch
* is performed in _ISR_Handler. These variables contain pointers
* to the lowest and highest addresses in the chunk of memory allocated
* for the interrupt stack. Since it is unknown whether the stack
* grows up or down (in general), this give the CPU dependent
- * code the option of picking the version it wants to use.
+ * code the option of picking the version it wants to use. Thus
+ * both must be present if either is.
*
- * NOTE: These two variables are required if the macro
- * CPU_HAS_SOFTWARE_INTERRUPT_STACK is defined as TRUE.
+ * The SPARC supports a software based interrupt stack and these
+ * are required.
*/
-EXTERN void *_CPU_Interrupt_stack_low;
-EXTERN void *_CPU_Interrupt_stack_high;
+EXTERN void *_CPU_Interrupt_stack_low;
+EXTERN void *_CPU_Interrupt_stack_high;
+
+#if defined(erc32)
/*
- * With some compilation systems, it is difficult if not impossible to
- * call a high-level language routine from assembly language. This
- * is especially true of commercial Ada compilers and name mangling
- * C++ ones. This variable can be optionally defined by the CPU porter
- * and contains the address of the routine _Thread_Dispatch. This
- * can make it easier to invoke that routine at the end of the interrupt
- * sequence (if a dispatch is necessary).
+ * ERC32 Specific Variables
*/
-EXTERN void (*_CPU_Thread_dispatch_pointer)();
+EXTERN unsigned32 _ERC32_MEC_Timer_Control_Mirror;
+#endif
+
+/*
+ * The following type defines an entry in the SPARC's trap table.
+ *
+ * NOTE: The instructions chosen are RTEMS dependent although one is
+ * obligated to use two of the four instructions to perform a
+ * long jump. The other instructions load one register with the
+ * trap type (a.k.a. vector) and another with the psr.
+ */
+
+typedef struct {
+ unsigned32 mov_psr_l0; /* mov %psr, %l0 */
+ unsigned32 sethi_of_handler_to_l4; /* sethi %hi(_handler), %l4 */
+ unsigned32 jmp_to_low_of_handler_plus_l4; /* jmp %l4 + %lo(_handler) */
+ unsigned32 mov_vector_l3; /* mov _vector, %l3 */
+} CPU_Trap_table_entry;
+
/*
- * Nothing prevents the porter from declaring more CPU specific variables.
+ * This is the set of opcodes for the instructions loaded into a trap
+ * table entry. The routine which installs a handler is responsible
+ * for filling in the fields for the _handler address and the _vector
+ * trap type.
+ *
+ * The constants following this structure are masks for the fields which
+ * must be filled in when the handler is installed.
*/
+
+extern const CPU_Trap_table_entry _CPU_Trap_slot_template;
-/* XXX: if needed, put more variables here */
+/*
+ * This is the executive's trap table which is installed into the TBR
+ * register.
+ *
+ * NOTE: Unfortunately, this must be aligned on a 4096 byte boundary.
+ * The GNU tools as of binutils 2.5.2 and gcc 2.7.0 would not
+ * align an entity to anything greater than a 512 byte boundary.
+ *
+ * Because of this, we pull a little bit of a trick. We allocate
+ * enough memory so we can grab an address on a 4096 byte boundary
+ * from this area.
+ */
+
+#define SPARC_TRAP_TABLE_ALIGNMENT 4096
+
+EXTERN unsigned8 _CPU_Trap_Table_area[ 8192 ]
+ __attribute__ ((aligned (SPARC_TRAP_TABLE_ALIGNMENT)));
+
/*
- * The size of the floating point context area. On some CPUs this
- * will not be a "sizeof" because the format of the floating point
- * area is not defined -- only the size is. This is usually on
- * CPUs with a "floating point save context" instruction.
+ * The size of the floating point context area.
*/
#define CPU_CONTEXT_FP_SIZE sizeof( Context_Control_fp )
+#endif
+
/*
* Amount of extra stack (above minimum stack size) required by
* system initialization thread. Remember that in a multiprocessor
@@ -538,23 +595,55 @@ EXTERN void (*_CPU_Thread_dispatch_pointer)();
/*
* This defines the number of entries in the ISR_Vector_table managed
* by the executive.
+ *
+ * On the SPARC, there are really only 256 vectors. However, the executive
+ * has no easy, fast, reliable way to determine which traps are synchronous
+ * and which are asynchronous. By default, synchronous traps return to the
+ * instruction which caused the interrupt. So if you install a software
+ * trap handler as an executive interrupt handler (which is desirable since
+ * RTEMS takes care of window and register issues), then the executive needs
+ * to know that the return address is to the trap rather than the instruction
+ * following the trap.
+ *
+ * So vectors 0 through 255 are treated as regular asynchronous traps which
+ * provide the "correct" return address. Vectors 256 through 512 are assumed
+ * by the executive to be synchronous and to require that the return address
+ * be fudged.
+ *
+ * If you use this mechanism to install a trap handler which must reexecute
+ * the instruction which caused the trap, then it should be installed as
+ * an asynchronous trap. This will avoid the executive changing the return
+ * address.
*/
-#define CPU_INTERRUPT_NUMBER_OF_VECTORS 255
+#define CPU_INTERRUPT_NUMBER_OF_VECTORS 256
+#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER 511
+
+#define SPARC_SYNCHRONOUS_TRAP_BIT_MASK 0x100
+#define SPARC_ASYNCHRONOUS_TRAP( _trap ) (_trap)
+#define SPARC_SYNCHRONOUS_TRAP( _trap ) ((_trap) + 256 )
+
+#define SPARC_REAL_TRAP_NUMBER( _trap ) ((_trap) % 256)
/*
* Should be large enough to run all tests. This insures
* that a "reasonable" small application should not have any problems.
+ *
+ * This appears to be a fairly generous number for the SPARC since
+ * represents a call depth of about 20 routines based on the minimum
+ * stack frame.
*/
-#define CPU_STACK_MINIMUM_SIZE (1024*2)
+#define CPU_STACK_MINIMUM_SIZE (1024*2)
/*
* CPU's worst alignment requirement for data types on a byte boundary. This
* alignment does not take into account the requirements for the stack.
+ *
+ * On the SPARC, this is required for double word loads and stores.
*/
-#define CPU_ALIGNMENT 8
+#define CPU_ALIGNMENT 8
/*
* This number corresponds to the byte alignment requirement for the
@@ -591,12 +680,15 @@ EXTERN void (*_CPU_Thread_dispatch_pointer)();
* is strict enough for the stack, then this should be set to 0.
*
* NOTE: This must be a power of 2 either 0 or greater than CPU_ALIGNMENT.
+ *
+ * The alignment restrictions for the SPARC are not that strict but this
+ * should unsure that the stack is always sufficiently alignment that the
+ * window overflow, underflow, and flush routines can use double word loads
+ * and stores.
*/
#define CPU_STACK_ALIGNMENT 16
-#endif /* ASM */
-
#ifndef ASM
/* ISR handler macros */
@@ -631,12 +723,7 @@ EXTERN void (*_CPU_Thread_dispatch_pointer)();
/*
* Map interrupt level in task mode onto the hardware that the CPU
* actually provides. Currently, interrupt levels which do not
- * map onto the CPU in a generic fashion are undefined. Someday,
- * it would be nice if these were "mapped" by the application
- * via a callout. For example, m68k has 8 levels 0 - 7, levels
- * 8 - 255 would be available for bsp/application specific meaning.
- * This could be used to manage a programmable interrupt controller
- * via the rtems_task_mode directive.
+ * map onto the CPU in a straight fashion are undefined.
*/
#define _CPU_ISR_Set_level( _newlevel ) \
@@ -659,46 +746,33 @@ unsigned32 _CPU_ISR_Get_level( void );
* - setting the proper interrupt level in the context
* - initializing the floating point context
*
- * This routine generally does not set any unnecessary register
- * in the context. The state of the "general data" registers is
- * undefined at task start time.
- *
* NOTE: Implemented as a subroutine for the SPARC port.
*/
void _CPU_Context_Initialize(
- Context_Control *_the_context,
- unsigned32 *_stack_base,
- unsigned32 _size,
- unsigned32 _new_level,
- void *_entry_point
+ Context_Control *the_context,
+ unsigned32 *stack_base,
+ unsigned32 size,
+ unsigned32 new_level,
+ void *entry_point,
+ boolean is_fp
);
/*
* This routine is responsible for somehow restarting the currently
- * executing task. If you are lucky, then all that is necessary
- * is restoring the context. Otherwise, there will need to be
- * a special assembly routine which does something special in this
- * case. Context_Restore should work most of the time. It will
- * not work if restarting self conflicts with the stack frame
- * assumptions of restoring a context.
+ * executing task.
+ *
+ * On the SPARC, this is is relatively painless but requires a small
+ * amount of wrapper code before using the regular restore code in
+ * of the context switch.
*/
#define _CPU_Context_Restart_self( _the_context ) \
_CPU_Context_restore( (_the_context) );
/*
- * The purpose of this macro is to allow the initial pointer into
- * a floating point context area (used to save the floating point
- * context) to be at an arbitrary place in the floating point
- * context area.
- *
- * This is necessary because some FP units are designed to have
- * their context saved as a stack which grows into lower addresses.
- * Other FP units can be saved by simply moving registers into offsets
- * from the base of the context area. Finally some FP units provide
- * a "dump context" instruction which could fill in from high to low
- * or low to high based on the whim of the CPU designers.
+ * The FP context area for the SPARC is a simple structure and nothing
+ * special is required to find the "starting load point"
*/
#define _CPU_Context_Fp_start( _base, _offset ) \
@@ -706,20 +780,17 @@ void _CPU_Context_Initialize(
/*
* This routine initializes the FP context area passed to it to.
- * There are a few standard ways in which to initialize the
- * floating point context. The code included for this macro assumes
- * that this is a CPU in which a "initial" FP context was saved into
- * _CPU_Null_fp_context and it simply copies it to the destination
- * context passed to it.
*
- * Other models include (1) not doing anything, and (2) putting
- * a "null FP status word" in the correct place in the FP context.
+ * The SPARC allows us to use the simple initialization model
+ * in which an "initial" FP context was saved into _CPU_Null_fp_context
+ * at CPU initialization and it is simply copied into the destination
+ * context.
*/
#define _CPU_Context_Initialize_fp( _destination ) \
- { \
+ do { \
*((Context_Control_fp *) *((void **) _destination)) = _CPU_Null_fp_context; \
- }
+ } while (0)
/* end of Context handler macros */
@@ -732,122 +803,42 @@ void _CPU_Context_Initialize(
*/
#define _CPU_Fatal_halt( _error ) \
- { \
- }
+ do { \
+ unsigned32 level; \
+ \
+ sparc_disable_interrupts( level ); \
+ asm volatile ( "mov %0, %%g1 " : "=r" (level) : "0" (level) ); \
+ while (1); /* loop forever */ \
+ } while (0)
/* end of Fatal Error manager macros */
/* Bitfield handler macros */
/*
- * This routine sets _output to the bit number of the first bit
- * set in _value. _value is of CPU dependent type Priority_Bit_map_control.
- * This type may be either 16 or 32 bits wide although only the 16
- * least significant bits will be used.
- *
- * There are a number of variables in using a "find first bit" type
- * instruction.
- *
- * (1) What happens when run on a value of zero?
- * (2) Bits may be numbered from MSB to LSB or vice-versa.
- * (3) The numbering may be zero or one based.
- * (4) The "find first bit" instruction may search from MSB or LSB.
- *
- * The executive guarantees that (1) will never happen so it is not a concern.
- * (2),(3), (4) are handled by the macros _CPU_Priority_mask() and
- * _CPU_Priority_Bits_index(). These three form a set of routines
- * which must logically operate together. Bits in the _value are
- * set and cleared based on masks built by _CPU_Priority_mask().
- * The basic major and minor values calculated by _Priority_Major()
- * and _Priority_Minor() are "massaged" by _CPU_Priority_Bits_index()
- * to properly range between the values returned by the "find first bit"
- * instruction. This makes it possible for _Priority_Get_highest() to
- * calculate the major and directly index into the minor table.
- * This mapping is necessary to ensure that 0 (a high priority major/minor)
- * is the first bit found.
- *
- * This entire "find first bit" and mapping process depends heavily
- * on the manner in which a priority is broken into a major and minor
- * components with the major being the 4 MSB of a priority and minor
- * the 4 LSB. Thus (0 << 4) + 0 corresponds to priority 0 -- the highest
- * priority. And (15 << 4) + 14 corresponds to priority 254 -- the next
- * to the lowest priority.
- *
- * If your CPU does not have a "find first bit" instruction, then
- * there are ways to make do without it. Here are a handful of ways
- * to implement this in software:
- *
- * - a series of 16 bit test instructions
- * - a "binary search using if's"
- * - _number = 0
- * if _value > 0x00ff
- * _value >>=8
- * _number = 8;
- *
- * if _value > 0x0000f
- * _value >=8
- * _number += 4
- *
- * _number += bit_set_table[ _value ]
- *
- * where bit_set_table[ 16 ] has values which indicate the first
- * bit set
- */
-
-#ifndef INIT
- extern const unsigned char __log2table[256];
+ * The SPARC port uses the generic C algorithm for bitfield scan if the
+ * CPU model does not have a scan instruction.
+ */
+
+#if ( SPARC_HAS_BITSCAN == 0 )
+#define CPU_USE_GENERIC_BITFIELD_CODE TRUE
+#define CPU_USE_GENERIC_BITFIELD_DATA TRUE
#else
-const unsigned char __log2table[256] = {
- 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
-};
+#error "scan instruction not currently supported by RTEMS!!"
#endif
-#define _CPU_Bitfield_Find_first_bit( _value, _output ) \
- { \
- register __value = (_value); \
- \
- if ( !(__value & 0xff00) ) \
- (_output) = __log2table[ __value ]; \
- else \
- (_output) = __log2table[ __value >> 8 ] + 8; \
- }
-
-
/* end of Bitfield handler macros */
-/*
- * This routine builds the mask which corresponds to the bit fields
- * as searched by _CPU_Bitfield_Find_first_bit(). See the discussion
- * for that routine.
- */
-
-#define _CPU_Priority_Mask( _bit_number ) \
- ( 0x8000 >> (_bit_number) )
+/* Priority handler handler macros */
/*
- * This routine translates the bit numbers returned by
- * _CPU_Bitfield_Find_first_bit() into something suitable for use as
- * a major or minor component of a priority. See the discussion
- * for that routine.
+ * The SPARC port uses the generic C algorithm for bitfield scan if the
+ * CPU model does not have a scan instruction.
*/
-#define _CPU_Priority_Bits_index( _priority ) \
- (15 - (_priority))
+#if ( SPARC_HAS_BITSCAN == 1 )
+#error "scan instruction not currently supported by RTEMS!!"
+#endif
/* end of Priority handler macros */
@@ -865,38 +856,42 @@ void _CPU_Initialize(
);
/*
- * _CPU_ISR_install_vector
+ * _CPU_ISR_install_raw_handler
*
- * This routine installs an interrupt vector.
+ * This routine installs new_handler to be directly called from the trap
+ * table.
*/
-
-void _CPU_ISR_install_vector(
+
+void _CPU_ISR_install_raw_handler(
unsigned32 vector,
proc_ptr new_handler,
proc_ptr *old_handler
);
/*
- * _CPU_Install_interrupt_stack
- *
- * This routine installs the hardware interrupt stack pointer.
+ * _CPU_ISR_install_vector
*
- * NOTE: It need only be provided if CPU_HAS_HARDWARE_INTERRUPT_STACK
- * is TRUE.
+ * This routine installs an interrupt vector.
*/
-void _CPU_Install_interrupt_stack( void );
+void _CPU_ISR_install_vector(
+ unsigned32 vector,
+ proc_ptr new_handler,
+ proc_ptr *old_handler
+);
+#if (CPU_PROVIDES_IDLE_THREAD_BODY == TRUE)
+
/*
* _CPU_Internal_threads_Idle_thread_body
*
- * This routine is the CPU dependent IDLE thread body.
- *
- * NOTE: It need only be provided if CPU_PROVIDES_IDLE_THREAD_BODY
- * is TRUE.
+ * Some SPARC implementations have low power, sleep, or idle modes. This
+ * tries to take advantage of those models.
*/
-
+
void _CPU_Internal_threads_Idle_thread_body( void );
+
+#endif /* CPU_PROVIDES_IDLE_THREAD_BODY */
/*
* _CPU_Context_switch
@@ -913,9 +908,7 @@ void _CPU_Context_switch(
* _CPU_Context_restore
*
* This routine is generallu used only to restart self in an
- * efficient manner. It may simply be a label in _CPU_Context_switch.
- *
- * NOTE: May be unnecessary to reload some registers.
+ * efficient manner.
*/
void _CPU_Context_restore(
@@ -942,24 +935,23 @@ void _CPU_Context_restore_fp(
void **fp_context_ptr
);
-/* The following routine swaps the endian format of an unsigned int.
+/*
+ * CPU_swap_u32
+ *
+ * The following routine swaps the endian format of an unsigned int.
* It must be static because it is referenced indirectly.
*
- * This version will work on any processor, but if there is a better
- * way for your CPU PLEASE use it. The most common way to do this is to:
+ * This version will work on any processor, but if you come across a better
+ * way for the SPARC PLEASE use it. The most common way to swap a 32-bit
+ * entity as shown below is not any more efficient on the SPARC.
*
* swap least significant two bytes with 16-bit rotate
* swap upper and lower 16-bits
* swap most significant two bytes with 16-bit rotate
*
- * Some CPUs have special instructions which swap a 32-bit quantity in
- * a single instruction (e.g. i486). It is probably best to avoid
- * an "endian swapping control bit" in the CPU. One good reason is
- * that interrupts would probably have to be disabled to insure that
- * an interrupt does not try to access the same "chunk" with the wrong
- * endian. Another good reason is that on some CPUs, the endian bit
- * endianness for ALL fetches -- both code and data -- so the code
- * will be fetched incorrectly.
+ * It is not obvious how the SPARC can do significantly better than the
+ * generic code. gcc 2.7.0 only generates about 12 instructions for the
+ * following code at optimization level four (i.e. -O4).
*/
static inline unsigned int CPU_swap_u32(
diff --git a/c/src/exec/score/cpu/sparc/cpu_asm.s b/c/src/exec/score/cpu/sparc/cpu_asm.s
index d1e275ca3f..045157b074 100644
--- a/c/src/exec/score/cpu/sparc/cpu_asm.s
+++ b/c/src/exec/score/cpu/sparc/cpu_asm.s
@@ -2,7 +2,7 @@
*
* This file contains the basic algorithms for all assembly code used
* in an specific CPU port of RTEMS. These algorithms must be implemented
- * in assembly language
+ * in assembly language.
*
* $Id$
*/
@@ -10,319 +10,680 @@
#include <asm.h>
#include <rtems/score/cpu.h>
+#if (SPARC_HAS_FPU == 1)
+
/*
- * _CPU_Context_save_fp
+ * void _CPU_Context_save_fp(
+ * void **fp_context_ptr
+ * )
*
* This routine is responsible for saving the FP context
* at *fp_context_ptr. If the point to load the FP context
* from is changed then the pointer is modified by this routine.
*
- * Sometimes a macro implementation of this is in cpu.h which dereferences
- * the ** and a similarly named routine in this file is passed something
- * like a (Context_Control_fp *). The general rule on making this decision
- * is to avoid writing assembly language.
- *
- * void _CPU_Context_save_fp(
- * void **fp_context_ptr
- * )
- * {
- * }
+ * NOTE: See the README in this directory for information on the
+ * management of the "EF" bit in the PSR.
*/
.align 4
PUBLIC(_CPU_Context_save_fp)
SYM(_CPU_Context_save_fp):
- save %sp,-104,%sp
- ld [%i0],%l0
- std %f0,[%l0+FO_F1_OFFSET]
- std %f2,[%l0+F2_F3_OFFSET]
- std %f4,[%l0+F4_F5_OFFSET]
- std %f6,[%l0+F6_F7_OFFSET]
- std %f8,[%l0+F8_F9_OFFSET]
- std %f10,[%l0+F1O_F11_OFFSET]
- std %f12,[%l0+F12_F13_OFFSET]
- std %f14,[%l0+F14_F15_OFFSET]
- std %f16,[%l0+F16_F17_OFFSET]
- std %f18,[%l0+F18_F19_OFFSET]
- std %f20,[%l0+F2O_F21_OFFSET]
- std %f22,[%l0+F22_F23_OFFSET]
- std %f24,[%l0+F24_F25_OFFSET]
- std %f26,[%l0+F26_F27_OFFSET]
- std %f28,[%l0+F28_F29_OFFSET]
- std %f30,[%l0+F3O_F31_OFFSET]
- st %fsr,[%l0+FSR_OFFSET]
+ save %sp, -CPU_MINIMUM_STACK_FRAME_SIZE, %sp
+
+ /*
+ * The following enables the floating point unit.
+ */
+
+ mov %psr, %l0
+ sethi %hi(SPARC_PSR_EF_MASK), %l1
+ or %l1, %lo(SPARC_PSR_EF_MASK), %l1
+ or %l0, %l1, %l0
+ mov %l0, %psr ! **** ENABLE FLOAT ACCESS ****
+
+ ld [%i0], %l0
+ std %f0, [%l0 + FO_F1_OFFSET]
+ std %f2, [%l0 + F2_F3_OFFSET]
+ std %f4, [%l0 + F4_F5_OFFSET]
+ std %f6, [%l0 + F6_F7_OFFSET]
+ std %f8, [%l0 + F8_F9_OFFSET]
+ std %f10, [%l0 + F1O_F11_OFFSET]
+ std %f12, [%l0 + F12_F13_OFFSET]
+ std %f14, [%l0 + F14_F15_OFFSET]
+ std %f16, [%l0 + F16_F17_OFFSET]
+ std %f18, [%l0 + F18_F19_OFFSET]
+ std %f20, [%l0 + F2O_F21_OFFSET]
+ std %f22, [%l0 + F22_F23_OFFSET]
+ std %f24, [%l0 + F24_F25_OFFSET]
+ std %f26, [%l0 + F26_F27_OFFSET]
+ std %f28, [%l0 + F28_F29_OFFSET]
+ std %f30, [%l0 + F3O_F31_OFFSET]
+ st %fsr, [%l0 + FSR_OFFSET]
ret
restore
/*
- * _CPU_Context_restore_fp
+ * void _CPU_Context_restore_fp(
+ * void **fp_context_ptr
+ * )
*
* This routine is responsible for restoring the FP context
* at *fp_context_ptr. If the point to load the FP context
* from is changed then the pointer is modified by this routine.
*
- * Sometimes a macro implementation of this is in cpu.h which dereferences
- * the ** and a similarly named routine in this file is passed something
- * like a (Context_Control_fp *). The general rule on making this decision
- * is to avoid writing assembly language.
- *
- * void _CPU_Context_restore_fp(
- * void **fp_context_ptr
- * )
- * {
- * }
+ * NOTE: See the README in this directory for information on the
+ * management of the "EF" bit in the PSR.
*/
.align 4
PUBLIC(_CPU_Context_restore_fp)
SYM(_CPU_Context_restore_fp):
- save %sp,-104,%sp
- ld [%o0],%l0
- ldd [%l0+FO_F1_OFFSET],%f0
- ldd [%l0+F2_F3_OFFSET],%f2
- ldd [%l0+F4_F5_OFFSET],%f4
- ldd [%l0+F6_F7_OFFSET],%f6
- ldd [%l0+F8_F9_OFFSET],%f8
- ldd [%l0+F1O_F11_OFFSET],%f10
- ldd [%l0+F12_F13_OFFSET],%f12
- ldd [%l0+F14_F15_OFFSET],%f14
- ldd [%l0+F16_F17_OFFSET],%f16
- ldd [%l0+F18_F19_OFFSET],%f18
- ldd [%l0+F2O_F21_OFFSET],%f20
- ldd [%l0+F22_F23_OFFSET],%f22
- ldd [%l0+F24_F25_OFFSET],%f24
- ldd [%l0+F26_F27_OFFSET],%f26
- ldd [%l0+F28_F29_OFFSET],%f28
- ldd [%l0+F3O_F31_OFFSET],%f30
- ld [%l0+FSR_OFFSET],%fsr
+ save %sp, -CPU_MINIMUM_STACK_FRAME_SIZE , %sp
+
+ /*
+ * The following enables the floating point unit.
+ */
+
+ mov %psr, %l0
+ sethi %hi(SPARC_PSR_EF_MASK), %l1
+ or %l1, %lo(SPARC_PSR_EF_MASK), %l1
+ or %l0, %l1, %l0
+ mov %l0, %psr ! **** ENABLE FLOAT ACCESS ****
+
+ ld [%i0], %l0
+ ldd [%l0 + FO_F1_OFFSET], %f0
+ ldd [%l0 + F2_F3_OFFSET], %f2
+ ldd [%l0 + F4_F5_OFFSET], %f4
+ ldd [%l0 + F6_F7_OFFSET], %f6
+ ldd [%l0 + F8_F9_OFFSET], %f8
+ ldd [%l0 + F1O_F11_OFFSET], %f10
+ ldd [%l0 + F12_F13_OFFSET], %f12
+ ldd [%l0 + F14_F15_OFFSET], %f14
+ ldd [%l0 + F16_F17_OFFSET], %f16
+ ldd [%l0 + F18_F19_OFFSET], %f18
+ ldd [%l0 + F2O_F21_OFFSET], %f20
+ ldd [%l0 + F22_F23_OFFSET], %f22
+ ldd [%l0 + F24_F25_OFFSET], %f24
+ ldd [%l0 + F26_F27_OFFSET], %f26
+ ldd [%l0 + F28_F29_OFFSET], %f28
+ ldd [%l0 + F3O_F31_OFFSET], %f30
+ ld [%l0 + FSR_OFFSET], %fsr
ret
restore
-/* _CPU_Context_switch
- *
- * This routine performs a normal non-FP context switch.
- *
+#endif /* SPARC_HAS_FPU */
+
+/*
* void _CPU_Context_switch(
* Context_Control *run,
* Context_Control *heir
* )
- * {
- * }
+ *
+ * This routine performs a normal non-FP context switch.
*/
-/* from gcc-2.7.0/config/sparc/sparc.h on register usage */
-
-/* 1 for registers that have pervasive standard uses
- and are not available for the register allocator.
- g0 is used for the condition code and not to represent %g0, which is
- hardwired to 0, so reg 0 is *not* fixed.
- On non-v9 systems:
- g1 is free to use as temporary.
- g2-g4 are reserved for applications. Gcc normally uses them as
- temporaries, but this can be disabled via the -mno-app-regs option.
- g5 through g7 are reserved for the operating system.
- On v9 systems:
- g1 and g5 are free to use as temporaries.
- g2-g4 are reserved for applications (the compiler will not normally use
- them, but they can be used as temporaries with -mapp-regs).
- g6-g7 are reserved for the operating system.
- ??? Register 1 is used as a temporary by the 64 bit sethi pattern, so must
- currently be a fixed register until this pattern is rewritten.
- Register 1 is also used when restoring call-preserved registers in large
- stack frames. */
-
-
.align 4
PUBLIC(_CPU_Context_switch)
SYM(_CPU_Context_switch):
- ta 0x03 /* flush registers */
-
- /* skip g0 */
- st %g1,[%o0+G1_OFFSET] /* globals */
- st %g2,[%o0+G2_OFFSET]
- st %g3,[%o0+G3_OFFSET]
- st %g4,[%o0+G4_OFFSET]
- st %g5,[%o0+G5_OFFSET]
- st %g6,[%o0+G6_OFFSET]
- st %g7,[%o0+G7_OFFSET]
-
- st %l0,[%o0+L0_OFFSET]
- st %l1,[%o0+L1_OFFSET]
- st %l2,[%o0+L2_OFFSET]
- st %l3,[%o0+L3_OFFSET]
- st %l4,[%o0+L4_OFFSET]
- st %l5,[%o0+L5_OFFSET]
- st %l6,[%o0+L6_OFFSET]
- st %l7,[%o0+L7_OFFSET]
-
- st %i0,[%o0+I0_OFFSET]
- st %i1,[%o0+I1_OFFSET]
- st %i2,[%o0+I2_OFFSET]
- st %i3,[%o0+I3_OFFSET]
- st %i4,[%o0+I4_OFFSET]
- st %i5,[%o0+I5_OFFSET]
- st %i6,[%o0+I6_OFFSET]
- st %i7,[%o0+I7_OFFSET]
-
- st %o0,[%o0+O0_OFFSET]
- st %o1,[%o0+O1_OFFSET]
- st %o2,[%o0+O2_OFFSET]
- st %o3,[%o0+O3_OFFSET]
- st %o4,[%o0+O4_OFFSET]
- st %o5,[%o0+O5_OFFSET]
- st %o6,[%o0+O6_OFFSET]
- st %o7,[%o0+O7_OFFSET]
-
- rd %psr,%o2
- st %o2,[%o0+PSR_OFFSET] /* save status register */
-
- /* enter here with o1 = context to restore */
- /* o2 = psr */
-restore:
-
- ld [%o1+PSR_OFFSET],%o0
- and %o2,31,%o2 /* g1 = cwp */
- and %o0,-32,%o0 /* o0 = psr w/o cwp */
- or %o0,%o2,%o2 /* o2 = new psr */
- wr %o2,0,%psr /* restore status register */
-
- /* skip g0 */
- ld [%o1+G1_OFFSET],%g1
- ld [%o1+G2_OFFSET],%g2
- ld [%o1+G3_OFFSET],%g3
- ld [%o1+G4_OFFSET],%g4
- ld [%o1+G5_OFFSET],%g5
- ld [%o1+G6_OFFSET],%g6
- ld [%o1+G7_OFFSET],%g7
-
- ld [%o1+L0_OFFSET],%l0
- ld [%o1+L1_OFFSET],%l1
- ld [%o1+L2_OFFSET],%l2
- ld [%o1+L3_OFFSET],%l3
- ld [%o1+L4_OFFSET],%l4
- ld [%o1+L5_OFFSET],%l5
- ld [%o1+L6_OFFSET],%l6
- ld [%o1+L7_OFFSET],%l7
-
- ld [%o1+I0_OFFSET],%i0
- ld [%o1+I1_OFFSET],%i1
- ld [%o1+I2_OFFSET],%i2
- ld [%o1+I3_OFFSET],%i3
- ld [%o1+I4_OFFSET],%i4
- ld [%o1+I5_OFFSET],%i5
- ld [%o1+I6_OFFSET],%i6
- ld [%o1+I7_OFFSET],%i7
-
- ld [%o1+O0_OFFSET],%o0
- /* do o1 last to avoid destroying heir context pointer */
- ld [%o1+O2_OFFSET],%o2
- ld [%o1+O3_OFFSET],%o3
- ld [%o1+O4_OFFSET],%o4
- ld [%o1+O5_OFFSET],%o5
- ld [%o1+O6_OFFSET],%o6
- ld [%o1+O7_OFFSET],%o7
-
- ld [%o1+O1_OFFSET],%o1 /* overwrite heir pointer */
-
- jmp %o7 + 8 /* return */
- nop /* delay slot */
-
+ ! skip g0
+ st %g1, [%o0 + G1_OFFSET] ! save the global registers
+ std %g2, [%o0 + G2_OFFSET]
+ std %g4, [%o0 + G4_OFFSET]
+ std %g6, [%o0 + G6_OFFSET]
+
+ std %l0, [%o0 + L0_OFFSET] ! save the local registers
+ std %l2, [%o0 + L2_OFFSET]
+ std %l4, [%o0 + L4_OFFSET]
+ std %l6, [%o0 + L6_OFFSET]
+
+ std %i0, [%o0 + I0_OFFSET] ! save the input registers
+ std %i2, [%o0 + I2_OFFSET]
+ std %i4, [%o0 + I4_OFFSET]
+ std %i6, [%o0 + I6_FP_OFFSET]
+
+ std %o0, [%o0 + O0_OFFSET] ! save the output registers
+ std %o2, [%o0 + O2_OFFSET]
+ std %o4, [%o0 + O4_OFFSET]
+ std %o6, [%o0 + O6_SP_OFFSET]
+
+ rd %psr, %o2
+ st %o2, [%o0 + PSR_OFFSET] ! save status register
+
+ /*
+ * This is entered from _CPU_Context_restore with:
+ * o1 = context to restore
+ * o2 = psr
+ */
+
+ PUBLIC(_CPU_Context_restore_heir)
+SYM(_CPU_Context_restore_heir):
+ /*
+ * Flush all windows with valid contents except the current one.
+ * In examining the set register windows, one may logically divide
+ * the windows into sets (some of which may be empty) based on their
+ * current status:
+ *
+ * + current (i.e. in use),
+ * + used (i.e. a restore would not trap)
+ * + invalid (i.e. 1 in corresponding bit in WIM)
+ * + unused
+ *
+ * Either the used or unused set of windows may be empty.
+ *
+ * NOTE: We assume only one bit is set in the WIM at a time.
+ *
+ * Given a CWP of 5 and a WIM of 0x1, the registers are divided
+ * into sets as follows:
+ *
+ * + 0 - invalid
+ * + 1-4 - unused
+ * + 5 - current
+ * + 6-7 - used
+ *
+ * In this case, we only would save the used windows -- 6 and 7.
+ *
+ * Traps are disabled for the same logical period as in a
+ * flush all windows trap handler.
+ *
+ * Register Usage while saving the windows:
+ * g1 = current PSR
+ * g2 = current wim
+ * g3 = CWP
+ * g4 = wim scratch
+ * g5 = scratch
+ */
+
+ ld [%o1 + PSR_OFFSET], %g1 ! g1 = saved psr
+
+ and %o2, SPARC_PSR_CWP_MASK, %g3 ! g3 = CWP
+ ! g1 = psr w/o cwp
+ andn %g1, SPARC_PSR_ET_MASK | SPARC_PSR_CWP_MASK, %g1
+ or %g1, %g3, %g1 ! g1 = heirs psr
+ mov %g1, %psr ! restore status register and
+ ! **** DISABLE TRAPS ****
+ mov %wim, %g2 ! g2 = wim
+ mov 1, %g4
+ sll %g4, %g3, %g4 ! g4 = WIM mask for CW invalid
+
+save_frame_loop:
+ sll %g4, 1, %g5 ! rotate the "wim" left 1
+ srl %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g4
+ or %g4, %g5, %g4 ! g4 = wim if we do one restore
+
+ /*
+ * If a restore would not underflow, then continue.
+ */
+
+ andcc %g4, %g2, %g0 ! Any windows to flush?
+ bnz done_flushing ! No, then continue
+ nop
+
+ restore ! back one window
+
+ /*
+ * Now save the window just as if we overflowed to it.
+ */
+
+ std %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
+ std %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
+ std %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
+ std %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
+
+ std %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
+ std %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
+ std %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
+ std %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
+
+ ba save_frame_loop
+ nop
+
+done_flushing:
+
+ add %g3, 1, %g3 ! calculate desired WIM
+ and %g3, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %g3
+ mov 1, %g4
+ sll %g4, %g3, %g4 ! g4 = new WIM
+ mov %g4, %wim
+
+ or %g1, SPARC_PSR_ET_MASK, %g1
+ mov %g1, %psr ! **** ENABLE TRAPS ****
+ ! and restore CWP
+ nop
+ nop
+ nop
+
+ ! skip g0
+ ld [%o1 + G1_OFFSET], %g1 ! restore the global registers
+ ldd [%o1 + G2_OFFSET], %g2
+ ldd [%o1 + G4_OFFSET], %g4
+ ldd [%o1 + G6_OFFSET], %g6
+
+ ldd [%o1 + L0_OFFSET], %l0 ! restore the local registers
+ ldd [%o1 + L2_OFFSET], %l2
+ ldd [%o1 + L4_OFFSET], %l4
+ ldd [%o1 + L6_OFFSET], %l6
+
+ ldd [%o1 + I0_OFFSET], %i0 ! restore the output registers
+ ldd [%o1 + I2_OFFSET], %i2
+ ldd [%o1 + I4_OFFSET], %i4
+ ldd [%o1 + I6_FP_OFFSET], %i6
+
+ ldd [%o1 + O2_OFFSET], %o2 ! restore the output registers
+ ldd [%o1 + O4_OFFSET], %o4
+ ldd [%o1 + O6_SP_OFFSET], %o6
+ ! do o0/o1 last to avoid destroying heir context pointer
+ ldd [%o1 + O0_OFFSET], %o0 ! overwrite heir pointer
+
+ jmp %o7 + 8 ! return
+ nop ! delay slot
/*
- * _CPU_Context_restore
- *
- * This routine is generallu used only to restart self in an
- * efficient manner. It may simply be a label in _CPU_Context_switch.
- *
- * NOTE: May be unnecessary to reload some registers.
- *
* void _CPU_Context_restore(
* Context_Control *new_context
* )
- * {
- * }
+ *
+ * This routine is generally used only to perform restart self.
+ *
+ * NOTE: It is unnecessary to reload some registers.
*/
.align 4
PUBLIC(_CPU_Context_restore)
SYM(_CPU_Context_restore):
- save %sp, -104, %sp /* save a stack frame */
- ta 0x03 /* flush registers */
- rd %psr,%o2
- ba restore
- mov %i0,%o1 /* in the delay slot */
+ save %sp, -CPU_MINIMUM_STACK_FRAME_SIZE, %sp
+ rd %psr, %o2
+ ba SYM(_CPU_Context_restore_heir)
+ mov %i0, %o1 ! in the delay slot
-/* void _ISR_Handler()
+/*
+ * void _ISR_Handler()
*
* This routine provides the RTEMS interrupt management.
*
- * void _ISR_Handler()
- * {
- * }
+ * We enter this handler from the 4 instructions in the trap table with
+ * the following registers assumed to be set as shown:
+ *
+ * l0 = PSR
+ * l1 = PC
+ * l2 = nPC
+ * l3 = trap type
+ *
+ * NOTE: By an executive defined convention, trap type is between 0 and 255 if
+ * it is an asynchonous trap and 256 and 511 if it is synchronous.
*/
.align 4
PUBLIC(_ISR_Handler)
SYM(_ISR_Handler):
- ret
+ /*
+ * Fix the return address for synchronous traps.
+ */
+
+ andcc %l3, SPARC_SYNCHRONOUS_TRAP_BIT_MASK, %g0
+ ! Is this a synchronous trap?
+ be,a win_ovflow ! No, then skip the adjustment
+ nop ! DELAY
+ mov %l2, %l1 ! do not return to the instruction
+ add %l2, 4, %l2 ! indicated
+
+win_ovflow:
+ /*
+ * Save the globals this block uses.
+ *
+ * These registers are not restored from the locals. Their contents
+ * are saved directly from the locals into the ISF below.
+ */
+
+ mov %g4, %l4 ! save the globals this block uses
+ mov %g5, %l5
+
+ /*
+ * When at a "window overflow" trap, (wim == (1 << cwp)).
+ * If we get here like that, then process a window overflow.
+ */
+
+ rd %wim, %g4
+ srl %g4, %l0, %g5 ! g5 = win >> cwp ; shift count and CWP
+ ! are LS 5 bits ; how convenient :)
+ cmp %g5, 1 ! Is this an invalid window?
+ bne dont_do_the_window ! No, then skip all this stuff
+ ! we are using the delay slot
+
+ /*
+ * The following is same as a 1 position right rotate of WIM
+ */
+
+ srl %g4, 1, %g5 ! g5 = WIM >> 1
+ sll %g4, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %g4
+ ! g4 = WIM << (Number Windows - 1)
+ or %g4, %g5, %g4 ! g4 = (WIM >> 1) |
+ ! (WIM << (Number Windows - 1))
+
+ /*
+ * At this point:
+ *
+ * g4 = the new WIM
+ * g5 is free
+ */
+
+ /*
+ * Since we are tinkering with the register windows, we need to
+ * make sure that all the required information is in global registers.
+ */
+
+ save ! Save into the window
+ wr %g4, 0, %wim ! WIM = new WIM
+ nop ! delay slots
+ nop
+ nop
+
+ /*
+ * Now save the window just as if we overflowed to it.
+ */
+
+ std %l0, [%sp + CPU_STACK_FRAME_L0_OFFSET]
+ std %l2, [%sp + CPU_STACK_FRAME_L2_OFFSET]
+ std %l4, [%sp + CPU_STACK_FRAME_L4_OFFSET]
+ std %l6, [%sp + CPU_STACK_FRAME_L6_OFFSET]
+
+ std %i0, [%sp + CPU_STACK_FRAME_I0_OFFSET]
+ std %i2, [%sp + CPU_STACK_FRAME_I2_OFFSET]
+ std %i4, [%sp + CPU_STACK_FRAME_I4_OFFSET]
+ std %i6, [%sp + CPU_STACK_FRAME_I6_FP_OFFSET]
+
+ restore
+ nop
+
+dont_do_the_window:
+ /*
+ * Global registers %g4 and %g5 are saved directly from %l4 and
+ * %l5 directly into the ISF below.
+ */
+
+save_isf:
+
+ /*
+ * Save the state of the interrupted task -- especially the global
+ * registers -- in the Interrupt Stack Frame. Note that the ISF
+ * includes a regular minimum stack frame which will be used if
+ * needed by register window overflow and underflow handlers.
+ *
+ * REGISTERS SAME AS AT _ISR_Handler
+ */
+
+ sub %fp, CONTEXT_CONTROL_INTERRUPT_FRAME_SIZE, %sp
+ ! make space for ISF
+
+ std %l0, [%sp + ISF_PSR_OFFSET] ! save psr, PC
+ st %l2, [%sp + ISF_NPC_OFFSET] ! save nPC
+ st %g1, [%sp + ISF_G1_OFFSET] ! save g1
+ std %g2, [%sp + ISF_G2_OFFSET] ! save g2, g3
+ std %l4, [%sp + ISF_G4_OFFSET] ! save g4, g5 -- see above
+ std %g6, [%sp + ISF_G6_OFFSET] ! save g6, g7
+
+ std %i0, [%sp + ISF_I0_OFFSET] ! save i0, i1
+ std %i2, [%sp + ISF_I2_OFFSET] ! save i2, i3
+ std %i4, [%sp + ISF_I4_OFFSET] ! save i4, i5
+ std %i6, [%sp + ISF_I6_FP_OFFSET] ! save i6/fp, i7
+
+ rd %y, %g1
+ st %g1, [%sp + ISF_Y_OFFSET] ! save y
+
+ mov %sp, %o1 ! 2nd arg to ISR Handler
+
+ /*
+ * Increment ISR nest level and Thread dispatch disable level.
+ *
+ * Register usage for this section:
+ *
+ * l4 = _Thread_Dispatch_disable_level pointer
+ * l5 = _ISR_Nest_level pointer
+ * l6 = _Thread_Dispatch_disable_level value
+ * l7 = _ISR_Nest_level value
+ *
+ * NOTE: It is assumed that l4 - l7 will be preserved until the ISR
+ * nest and thread dispatch disable levels are unnested.
+ */
+
+ sethi %hi(SYM(_Thread_Dispatch_disable_level)), %l4
+ ld [%l4 + %lo(SYM(_Thread_Dispatch_disable_level))], %l6
+ sethi %hi(SYM(_ISR_Nest_level)), %l5
+ ld [%l5 + %lo(SYM(_ISR_Nest_level))], %l7
+
+ add %l6, 1, %l6
+ st %l6, [%l4 + %lo(SYM(_Thread_Dispatch_disable_level))]
+
+ add %l7, 1, %l7
+ st %l7, [%l5 + %lo(SYM(_ISR_Nest_level))]
+
+ /*
+ * If ISR nest level was zero (now 1), then switch stack.
+ */
+
+ mov %sp, %fp
+ subcc %l7, 1, %l7 ! outermost interrupt handler?
+ bnz dont_switch_stacks ! No, then do not switch stacks
+
+ sethi %hi(SYM(_CPU_Interrupt_stack_high)), %g4
+ ld [%g4 + %lo(SYM(_CPU_Interrupt_stack_high))], %sp
+
+dont_switch_stacks:
+ /*
+ * Make sure we have a place on the stack for the window overflow
+ * trap handler to write into. At this point it is safe to
+ * enable traps again.
+ */
+
+ sub %sp, CPU_MINIMUM_STACK_FRAME_SIZE, %sp
+
+ wr %l0, SPARC_PSR_ET_MASK, %psr ! **** ENABLE TRAPS ****
+
+ /*
+ * Vector to user's handler.
+ *
+ * NOTE: TBR may no longer have vector number in it since
+ * we just enabled traps. It is definitely in l3.
+ */
+
+ sethi %hi(SYM(_ISR_Vector_table)), %g4
+ or %g4, %lo(SYM(_ISR_Vector_table)), %g4
+ and %l3, 0xFF, %g5 ! remove synchronous trap indicator
+ sll %g5, 2, %g5 ! g5 = offset into table
+ ld [%g4 + %g5], %g4 ! g4 = _ISR_Vector_table[ vector ]
+
+
+ ! o1 = 2nd arg = address of the ISF
+ ! WAS LOADED WHEN ISF WAS SAVED!!!
+ mov %l3, %o0 ! o0 = 1st arg = vector number
+ call %g4, 0
+ nop ! delay slot
+
+ /*
+ * Redisable traps so we can finish up the interrupt processing.
+ * This is a VERY conservative place to do this.
+ *
+ * NOTE: %l0 has the PSR which was in place when we took the trap.
+ */
+
+ mov %l0, %psr ! **** DISABLE TRAPS ****
+
+ /*
+ * Decrement ISR nest level and Thread dispatch disable level.
+ *
+ * Register usage for this section:
+ *
+ * l4 = _Thread_Dispatch_disable_level pointer
+ * l5 = _ISR_Nest_level pointer
+ * l6 = _Thread_Dispatch_disable_level value
+ * l7 = _ISR_Nest_level value
+ */
+
+ sub %l6, 1, %l6
+ st %l6, [%l4 + %lo(SYM(_Thread_Dispatch_disable_level))]
+
+ st %l7, [%l5 + %lo(SYM(_ISR_Nest_level))]
+
+ /*
+ * If dispatching is disabled (includes nested interrupt case),
+ * then do a "simple" exit.
+ */
+
+ orcc %l6, %g0, %g0 ! Is dispatching disabled?
+ bnz simple_return ! Yes, then do a "simple" exit
+ nop ! delay slot
+
+ /*
+ * If a context switch is necessary, then do fudge stack to
+ * return to the interrupt dispatcher.
+ */
+
+ sethi %hi(SYM(_Context_Switch_necessary)), %l4
+ ld [%l4 + %lo(SYM(_Context_Switch_necessary))], %l5
+
+ orcc %l5, %g0, %g0 ! Is thread switch necessary?
+ bnz SYM(_ISR_Dispatch) ! yes, then invoke the dispatcher
+ nop ! delay slot
+
+ /*
+ * Finally, check to see if signals were sent to the currently
+ * executing task. If so, we need to invoke the interrupt dispatcher.
+ */
+
+ sethi %hi(SYM(_ISR_Signals_to_thread_executing)), %l6
+ ld [%l6 + %lo(SYM(_ISR_Signals_to_thread_executing))], %l7
+
+ orcc %l7, %g0, %g0 ! Were signals sent to the currently
+ ! executing thread?
+ bz simple_return ! yes, then invoke the dispatcher
+ nop ! delay slot
+
+ /*
+ * Invoke interrupt dispatcher.
+ */
+
+ PUBLIC(_ISR_Dispatch)
+SYM(_ISR_Dispatch):
+
+ /*
+ * The following subtract should get us back on the interrupted
+ * tasks stack and add enough room to invoke the dispatcher.
+ * When we enable traps, we are mostly back in the context
+ * of the task and subsequent interrupts can operate normally.
+ */
+
+ sub %fp, CPU_MINIMUM_STACK_FRAME_SIZE, %sp
+
+ or %l0, SPARC_PSR_ET_MASK, %l7 ! l7 = PSR with ET=1
+ mov %l7, %psr ! **** ENABLE TRAPS ****
+ nop
+ nop
+ nop
+
+ call SYM(_Thread_Dispatch), 0
+ nop
+
+ /*
+ * The CWP in place at this point may be different from
+ * that which was in effect at the beginning of the ISR if we
+ * have been context switched between the beginning of this invocation
+ * of _ISR_Handler and this point. Thus the CWP and WIM should
+ * not be changed back to their values at ISR entry time. Any
+ * changes to the PSR must preserve the CWP.
+ */
+
+simple_return:
+ ld [%fp + ISF_Y_OFFSET], %l5 ! restore y
+ wr %l5, 0, %y
+
+ ldd [%fp + ISF_PSR_OFFSET], %l0 ! restore psr, PC
+ ld [%fp + ISF_NPC_OFFSET], %l2 ! restore nPC
+ rd %psr, %l3
+ and %l3, SPARC_PSR_CWP_MASK, %l3 ! want "current" CWP
+ andn %l0, SPARC_PSR_CWP_MASK, %l0 ! want rest from task
+ or %l3, %l0, %l0 ! install it later...
+ andn %l0, SPARC_PSR_ET_MASK, %l0
+
+ /*
+ * Restore tasks global and out registers
+ */
+
+ mov %fp, %g1
+
+ ! g1 is restored later
+ ldd [%fp + ISF_G2_OFFSET], %g2 ! restore g2, g3
+ ldd [%fp + ISF_G4_OFFSET], %g4 ! restore g4, g5
+ ldd [%fp + ISF_G6_OFFSET], %g6 ! restore g6, g7
+
+ ldd [%fp + ISF_I0_OFFSET], %i0 ! restore i0, i1
+ ldd [%fp + ISF_I2_OFFSET], %i2 ! restore i2, i3
+ ldd [%fp + ISF_I4_OFFSET], %i4 ! restore i4, i5
+ ldd [%fp + ISF_I6_FP_OFFSET], %i6 ! restore i6/fp, i7
+
+ /*
+ * Registers:
+ *
+ * ALL global registers EXCEPT G1 and the input registers have
+ * already been restored and thuse off limits.
+ *
+ * The following is the contents of the local registers:
+ *
+ * l0 = original psr
+ * l1 = return address (i.e. PC)
+ * l2 = nPC
+ * l3 = CWP
+ */
+
+ /*
+ * if (CWP + 1) is an invalid window then we need to reload it.
+ *
+ * WARNING: Traps should now be disabled
+ */
+
+ mov %l0, %psr ! **** DISABLE TRAPS ****
+ nop
+ nop
+ nop
+ rd %wim, %l4
+ add %l0, 1, %l6 ! l6 = cwp + 1
+ and %l6, SPARC_PSR_CWP_MASK, %l6 ! do the modulo on it
+ srl %l4, %l6, %l5 ! l5 = win >> cwp + 1 ; shift count
+ ! and CWP are conveniently LS 5 bits
+ cmp %l5, 1 ! Is tasks window invalid?
+ bne good_task_window
+
+ /*
+ * The following code is the same as a 1 position left rotate of WIM.
+ */
+
+ sll %l4, 1, %l5 ! l5 = WIM << 1
+ srl %l4, SPARC_NUMBER_OF_REGISTER_WINDOWS-1 , %l4
+ ! l4 = WIM >> (Number Windows - 1)
+ or %l4, %l5, %l4 ! l4 = (WIM << 1) |
+ ! (WIM >> (Number Windows - 1))
+
+ /*
+ * Now restore the window just as if we underflowed to it.
+ */
+
+ wr %l4, 0, %wim ! WIM = new WIM
+ restore ! now into the tasks window
+
+ ldd [%g1 + CPU_STACK_FRAME_L0_OFFSET], %l0
+ ldd [%g1 + CPU_STACK_FRAME_L2_OFFSET], %l2
+ ldd [%g1 + CPU_STACK_FRAME_L4_OFFSET], %l4
+ ldd [%g1 + CPU_STACK_FRAME_L6_OFFSET], %l6
+ ldd [%g1 + CPU_STACK_FRAME_I0_OFFSET], %i0
+ ldd [%g1 + CPU_STACK_FRAME_I2_OFFSET], %i2
+ ldd [%g1 + CPU_STACK_FRAME_I4_OFFSET], %i4
+ ldd [%g1 + CPU_STACK_FRAME_I6_FP_OFFSET], %i6
+ ! reload of sp clobbers ISF
+ save ! Back to ISR dispatch window
+
+good_task_window:
+
+ mov %l0, %psr ! **** DISABLE TRAPS ****
+ ! and restore condition codes.
+ ld [%g1 + ISF_G1_OFFSET], %g1 ! restore g1
+ jmp %l1 ! transfer control and
+ rett %l2 ! go back to tasks window
- /*
- * This discussion ignores a lot of the ugly details in a real
- * implementation such as saving enough registers/state to be
- * able to do something real. Keep in mind that the goal is
- * to invoke a user's ISR handler which is written in C and
- * uses a certain set of registers.
- *
- * Also note that the exact order is to a large extent flexible.
- * Hardware will dictate a sequence for a certain subset of
- * _ISR_Handler while requirements for setting
- */
-
- /*
- * At entry to "common" _ISR_Handler, the vector number must be
- * available. On some CPUs the hardware puts either the vector
- * number or the offset into the vector table for this ISR in a
- * known place. If the hardware does not give us this information,
- * then the assembly portion of RTEMS for this port will contain
- * a set of distinct interrupt entry points which somehow place
- * the vector number in a known place (which is safe if another
- * interrupt nests this one) and branches to _ISR_Handler.
- *
- * save some or all context on stack
- * may need to save some special interrupt information for exit
- *
- * #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
- * if ( _ISR_Nest_level == 0 )
- * switch to software interrupt stack
- * #endif
- *
- * _ISR_Nest_level++;
- *
- * _Thread_Dispatch_disable_level++;
- *
- * (*_ISR_Vector_table[ vector ])( vector );
- *
- * --_ISR_Nest_level;
- *
- * if ( _ISR_Nest_level )
- * goto the label "exit interrupt (simple case)"
- *
- * #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
- * restore stack
- * #endif
- *
- * if ( !_Context_Switch_necessary )
- * goto the label "exit interrupt (simple case)"
- *
- * if ( !_ISR_Signals_to_thread_executing )
- * goto the label "exit interrupt (simple case)"
- *
- * call _Thread_Dispatch() or prepare to return to _ISR_Dispatch
- *
- * prepare to get out of interrupt
- * return from interrupt (maybe to _ISR_Dispatch)
- *
- * LABEL "exit interrupt (simple case):
- * prepare to get out of interrupt
- * return from interrupt
- */
+/* end of file */
diff --git a/c/src/exec/score/cpu/sparc/erc32.h b/c/src/exec/score/cpu/sparc/erc32.h
new file mode 100644
index 0000000000..9a8b875c49
--- /dev/null
+++ b/c/src/exec/score/cpu/sparc/erc32.h
@@ -0,0 +1,503 @@
+/* erc32.h
+ *
+ * This include file contains information pertaining to the ERC32.
+ * The ERC32 is a custom SPARC V7 implementation based on the Cypress
+ * 601/602 chipset. This CPU has a number of on-board peripherals and
+ * was developed by the European Space Agency to target space applications.
+ *
+ * NOTE: Other than where absolutely required, this version currently
+ * supports only the peripherals and bits used by the basic board
+ * support package. This includes at least significant pieces of
+ * the following items:
+ *
+ * + UART Channels A and B
+ * + General Purpose Timer
+ * + Real Time Clock
+ * + Watchdog Timer (so it can be disabled)
+ * + Control Register (so powerdown mode can be enabled)
+ * + Memory Control Register
+ * + Interrupt Control
+ *
+ * $Id$
+ */
+
+#ifndef _INCLUDE_ERC32_h
+#define _INCLUDE_ERC32_h
+
+#include <rtems/score/sparc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Interrupt Sources
+ *
+ * The interrupt source numbers directly map to the trap type and to
+ * the bits used in the Interrupt Clear, Interrupt Force, Interrupt Mask,
+ * and the Interrupt Pending Registers.
+ */
+
+#define ERC32_INTERRUPT_MASKED_ERRORS 1
+#define ERC32_INTERRUPT_EXTERNAL_1 2
+#define ERC32_INTERRUPT_EXTERNAL_2 3
+#define ERC32_INTERRUPT_UART_A_RX_TX 4
+#define ERC32_INTERRUPT_UART_B_RX_TX 5
+#define ERC32_INTERRUPT_CORRECTABLE_MEMORY_ERROR 6
+#define ERC32_INTERRUPT_UART_ERROR 7
+#define ERC32_INTERRUPT_DMA_ACCESS_ERROR 8
+#define ERC32_INTERRUPT_DMA_TIMEOUT 9
+#define ERC32_INTERRUPT_EXTERNAL_3 10
+#define ERC32_INTERRUPT_EXTERNAL_4 11
+#define ERC32_INTERRUPT_GENERAL_PURPOSE_TIMER 12
+#define ERC32_INTERRUPT_REAL_TIME_CLOCK 13
+#define ERC32_INTERRUPT_EXTERNAL_5 14
+#define ERC32_INTERRUPT_WATCHDOG_TIMEOUT 15
+
+#ifndef ASM
+
+/*
+ * Trap Types for on-chip peripherals
+ *
+ * Source: Table 8 - Interrupt Trap Type and Default Priority Assignments
+ *
+ * NOTE: The priority level for each source corresponds to the least
+ * significant nibble of the trap type.
+ */
+
+#define ERC32_TRAP_TYPE( _source ) SPARC_ASYNCHRONOUS_TRAP((_source) + 0x10)
+
+#define ERC32_TRAP_SOURCE( _trap ) ((_trap) - 0x10)
+
+#define ERC32_Is_MEC_Trap( _trap ) \
+ ( (_trap) >= ERC32_TRAP_TYPE( ERC32_INTERRUPT_MASKED_ERRORS ) && \
+ (_trap) <= ERC32_TRAP_TYPE( ERC32_INTERRUPT_WATCHDOG_TIMEOUT ) )
+
+/*
+ * Structure for ERC32 memory mapped registers.
+ *
+ * Source: Section 3.25.2 - Register Address Map
+ *
+ * NOTE: There is only one of these structures per CPU, its base address
+ * is 0x01f80000, and the variable MEC is placed there by the
+ * linkcmds file.
+ */
+
+typedef struct {
+ volatile unsigned32 Control; /* offset 0x00 */
+ volatile unsigned32 Software_Reset; /* offset 0x04 */
+ volatile unsigned32 Power_Down; /* offset 0x08 */
+ volatile unsigned32 Unimplemented_0; /* offset 0x0c */
+ volatile unsigned32 Memory_Configuration; /* offset 0x10 */
+ volatile unsigned32 IO_Configuration; /* offset 0x14 */
+ volatile unsigned32 Wait_State_Configuration; /* offset 0x18 */
+ volatile unsigned32 Unimplemented_1; /* offset 0x1c */
+ volatile unsigned32 Memory_Access_0; /* offset 0x20 */
+ volatile unsigned32 Memory_Access_1; /* offset 0x24 */
+ volatile unsigned32 Unimplemented_2[ 7 ]; /* offset 0x28 */
+ volatile unsigned32 Interrupt_Shape; /* offset 0x44 */
+ volatile unsigned32 Interrupt_Pending; /* offset 0x48 */
+ volatile unsigned32 Interrupt_Mask; /* offset 0x4c */
+ volatile unsigned32 Interrupt_Clear; /* offset 0x50 */
+ volatile unsigned32 Interrupt_Force; /* offset 0x54 */
+ volatile unsigned32 Unimplemented_3[ 2 ]; /* offset 0x58 */
+ /* offset 0x60 */
+ volatile unsigned32 Watchdog_Program_and_Timeout_Acknowledge;
+ volatile unsigned32 Watchdog_Trap_Door_Set; /* offset 0x64 */
+ volatile unsigned32 Unimplemented_4[ 6 ]; /* offset 0x68 */
+ volatile unsigned32 Real_Time_Clock_Counter; /* offset 0x80 */
+ volatile unsigned32 Real_Time_Clock_Scalar; /* offset 0x84 */
+ volatile unsigned32 General_Purpose_Timer_Counter; /* offset 0x88 */
+ volatile unsigned32 General_Purpose_Timer_Scalar; /* offset 0x8c */
+ volatile unsigned32 Unimplemented_5[ 2 ]; /* offset 0x90 */
+ volatile unsigned32 Timer_Control; /* offset 0x98 */
+ volatile unsigned32 Unimplemented_6; /* offset 0x9c */
+ volatile unsigned32 System_Fault_Status; /* offset 0xa0 */
+ volatile unsigned32 First_Failing_Address; /* offset 0xa4 */
+ volatile unsigned32 First_Failing_Data; /* offset 0xa8 */
+ volatile unsigned32 First_Failing_Syndrome_and_Check_Bits;/* offset 0xac */
+ volatile unsigned32 Error_and_Reset_Status; /* offset 0xb0 */
+ volatile unsigned32 Error_Mask; /* offset 0xb4 */
+ volatile unsigned32 Unimplemented_7[ 2 ]; /* offset 0xb8 */
+ volatile unsigned32 Debug_Control; /* offset 0xc0 */
+ volatile unsigned32 Breakpoint; /* offset 0xc4 */
+ volatile unsigned32 Watchpoint; /* offset 0xc8 */
+ volatile unsigned32 Unimplemented_8; /* offset 0xcc */
+ volatile unsigned32 Test_Control; /* offset 0xd0 */
+ volatile unsigned32 Test_Data; /* offset 0xd4 */
+ volatile unsigned32 Unimplemented_9[ 2 ]; /* offset 0xd8 */
+ volatile unsigned32 UART_Channel_A; /* offset 0xe0 */
+ volatile unsigned32 UART_Channel_B; /* offset 0xe4 */
+ volatile unsigned32 UART_Status; /* offset 0xe8 */
+} ERC32_Register_Map;
+
+#endif
+
+/*
+ * The following constants are intended to be used ONLY in assembly
+ * language files.
+ *
+ * NOTE: The intended style of usage is to load the address of MEC
+ * into a register and then use these as displacements from
+ * that register.
+ */
+
+#ifdef ASM
+
+#define ERC32_MEC_CONTROL_OFFSET 0x00
+#define ERC32_MEC_SOFTWARE_RESET_OFFSET 0x04
+#define ERC32_MEC_POWER_DOWN_OFFSET 0x08
+#define ERC32_MEC_UNIMPLEMENTED_0_OFFSET 0x0C
+#define ERC32_MEC_MEMORY_CONFIGURATION_OFFSET 0x10
+#define ERC32_MEC_IO_CONFIGURATION_OFFSET 0x14
+#define ERC32_MEC_WAIT_STATE_CONFIGURATION_OFFSET 0x18
+#define ERC32_MEC_UNIMPLEMENTED_1_OFFSET 0x1C
+#define ERC32_MEC_MEMORY_ACCESS_0_OFFSET 0x20
+#define ERC32_MEC_MEMORY_ACCESS_1_OFFSET 0x24
+#define ERC32_MEC_UNIMPLEMENTED_2_OFFSET 0x28
+#define ERC32_MEC_INTERRUPT_SHAPE_OFFSET 0x44
+#define ERC32_MEC_INTERRUPT_PENDING_OFFSET 0x48
+#define ERC32_MEC_INTERRUPT_MASK_OFFSET 0x4C
+#define ERC32_MEC_INTERRUPT_CLEAR_OFFSET 0x50
+#define ERC32_MEC_INTERRUPT_FORCE_OFFSET 0x54
+#define ERC32_MEC_UNIMPLEMENTED_3_OFFSET 0x58
+#define ERC32_MEC_WATCHDOG_PROGRAM_AND_TIMEOUT_ACKNOWLEDGE_OFFSET 0x60
+#define ERC32_MEC_WATCHDOG_TRAP_DOOR_SET_OFFSET 0x64
+#define ERC32_MEC_UNIMPLEMENTED_4_OFFSET 0x6C
+#define ERC32_MEC_REAL_TIME_CLOCK_COUNTER_OFFSET 0x80
+#define ERC32_MEC_REAL_TIME_CLOCK_SCALAR_OFFSET 0x84
+#define ERC32_MEC_GENERAL_PURPOSE_TIMER_COUNTER_OFFSET 0x88
+#define ERC32_MEC_GENERAL_PURPOSE_TIMER_SCALAR_OFFSET 0x8C
+#define ERC32_MEC_UNIMPLEMENTED_5_OFFSET 0x90
+#define ERC32_MEC_TIMER_CONTROL_OFFSET 0x98
+#define ERC32_MEC_UNIMPLEMENTED_6_OFFSET 0x9C
+#define ERC32_MEC_SYSTEM_FAULT_STATUS_OFFSET 0xA0
+#define ERC32_MEC_FIRST_FAILING_ADDRESS_OFFSET 0xA4
+#define ERC32_MEC_FIRST_FAILING_DATA_OFFSET 0xA8
+#define ERC32_MEC_FIRST_FAILING_SYNDROME_AND_CHECK_BITS_OFFSET 0xAC
+#define ERC32_MEC_ERROR_AND_RESET_STATUS_OFFSET 0xB0
+#define ERC32_MEC_ERROR_MASK_OFFSET 0xB4
+#define ERC32_MEC_UNIMPLEMENTED_7_OFFSET 0xB8
+#define ERC32_MEC_DEBUG_CONTROL_OFFSET 0xC0
+#define ERC32_MEC_BREAKPOINT_OFFSET 0xC4
+#define ERC32_MEC_WATCHPOINT_OFFSET 0xC8
+#define ERC32_MEC_UNIMPLEMENTED_8_OFFSET 0xCC
+#define ERC32_MEC_TEST_CONTROL_OFFSET 0xD0
+#define ERC32_MEC_TEST_DATA_OFFSET 0xD4
+#define ERC32_MEC_UNIMPLEMENTED_9_OFFSET 0xD8
+#define ERC32_MEC_UART_CHANNEL_A_OFFSET 0xE0
+#define ERC32_MEC_UART_CHANNEL_B_OFFSET 0xE4
+#define ERC32_MEC_UART_STATUS_OFFSET 0xE8
+
+#endif
+
+/*
+ * The following defines the bits in the Configuration Register.
+ */
+
+#define ERC32_CONFIGURATION_POWER_DOWN_MASK 0x00000001
+#define ERC32_CONFIGURATION_POWER_DOWN_ALLOWED 0x00000001
+#define ERC32_CONFIGURATION_POWER_DOWN_DISABLED 0x00000000
+
+#define ERC32_CONFIGURATION_SOFTWARE_RESET_MASK 0x00000002
+#define ERC32_CONFIGURATION_SOFTWARE_RESET_ALLOWED 0x00000002
+#define ERC32_CONFIGURATION_SOFTWARE_RESET_DISABLED 0x00000000
+
+#define ERC32_CONFIGURATION_BUS_TIMEOUT_MASK 0x00000004
+#define ERC32_CONFIGURATION_BUS_TIMEOUT_ENABLED 0x00000004
+#define ERC32_CONFIGURATION_BUS_TIMEOUT_DISABLED 0x00000000
+
+#define ERC32_CONFIGURATION_ACCESS_PROTECTION_MASK 0x00000008
+#define ERC32_CONFIGURATION_ACCESS_PROTECTION_ENABLED 0x00000008
+#define ERC32_CONFIGURATION_ACCESS_PROTECTION_DISABLED 0x00000000
+
+
+/*
+ * The following defines the bits in the Memory Configuration Register.
+ */
+
+#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_MASK 0x00001C00
+#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_256K ( 0 << 10 )
+#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_512K ( 1 << 10 )
+#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_1MB ( 2 << 10 )
+#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_2MB ( 3 << 10 )
+#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_4MB ( 4 << 10 )
+#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_8MB ( 5 << 10 )
+#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_16MB ( 6 << 10 )
+#define ERC32_MEMORY_CONFIGURATION_RAM_SIZE_32MB ( 7 << 10 )
+
+#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_MASK 0x001C0000
+#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_4K ( 0 << 18 )
+#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_8K ( 1 << 18 )
+#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_16K ( 2 << 18 )
+#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_32K ( 3 << 18 )
+#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_64K ( 4 << 18 )
+#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_128K ( 5 << 18 )
+#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_256K ( 6 << 18 )
+#define ERC32_MEMORY_CONFIGURATION_PROM_SIZE_512K ( 7 << 18 )
+
+/*
+ * The following defines the bits in the Timer Control Register.
+ */
+
+#define ERC32_MEC_TIMER_CONTROL_GCR 0x00000001 /* 1 = reload at 0 */
+ /* 0 = stop at 0 */
+#define ERC32_MEC_TIMER_CONTROL_GCL 0x00000002 /* 1 = load and start */
+ /* 0 = no function */
+#define ERC32_MEC_TIMER_CONTROL_GSE 0x00000004 /* 1 = enable counting */
+ /* 0 = hold scalar and counter */
+#define ERC32_MEC_TIMER_CONTROL_GSL 0x00000008 /* 1 = load scalar and start */
+ /* 0 = no function */
+
+#define ERC32_MEC_TIMER_CONTROL_RTCCR 0x00000100 /* 1 = reload at 0 */
+ /* 0 = stop at 0 */
+#define ERC32_MEC_TIMER_CONTROL_RTCCL 0x00000200 /* 1 = load and start */
+ /* 0 = no function */
+#define ERC32_MEC_TIMER_CONTROL_RTCSE 0x00000400 /* 1 = enable counting */
+ /* 0 = hold scalar and counter */
+#define ERC32_MEC_TIMER_CONTROL_RTCSL 0x00000800 /* 1 = load scalar and start */
+ /* 0 = no function */
+
+/*
+ * The following defines the bits in the UART Control Registers.
+ *
+ * NOTE: Same bits in UART channels A and B.
+ */
+
+#define ERC32_MEC_UART_CONTROL_RTD 0x000000FF /* RX/TX data */
+#define ERC32_MEC_UART_CONTROL_DR 0x00000100 /* RX Data Ready */
+#define ERC32_MEC_UART_CONTROL_TSE 0x00000200 /* TX Send Empty */
+ /* (i.e. no data to send) */
+#define ERC32_MEC_UART_CONTROL_THE 0x00000400 /* TX Hold Empty */
+ /* (i.e. ready to load) */
+
+/*
+ * The following defines the bits in the MEC UART Control Registers.
+ */
+
+#define ERC32_MEC_UART_STATUS_DR 0x00000001 /* Data Ready */
+#define ERC32_MEC_UART_STATUS_TSE 0x00000002 /* TX Send Register Empty */
+#define ERC32_MEC_UART_STATUS_THE 0x00000004 /* TX Hold Register Empty */
+#define ERC32_MEC_UART_STATUS_FE 0x00000010 /* RX Framing Error */
+#define ERC32_MEC_UART_STATUS_PE 0x00000020 /* RX Parity Error */
+#define ERC32_MEC_UART_STATUS_OE 0x00000040 /* RX Overrun Error */
+#define ERC32_MEC_UART_STATUS_CU 0x00000080 /* Clear Errors */
+#define ERC32_MEC_UART_STATUS_TXE 0x00000006 /* TX Empty */
+
+#define ERC32_MEC_UART_STATUS_DRA (ERC32_MEC_UART_STATUS_DR << 0)
+#define ERC32_MEC_UART_STATUS_TSEA (ERC32_MEC_UART_STATUS_TSE << 0)
+#define ERC32_MEC_UART_STATUS_THEA (ERC32_MEC_UART_STATUS_THE << 0)
+#define ERC32_MEC_UART_STATUS_FEA (ERC32_MEC_UART_STATUS_FE << 0)
+#define ERC32_MEC_UART_STATUS_PEA (ERC32_MEC_UART_STATUS_PE << 0)
+#define ERC32_MEC_UART_STATUS_OEA (ERC32_MEC_UART_STATUS_OE << 0)
+#define ERC32_MEC_UART_STATUS_CUA (ERC32_MEC_UART_STATUS_CU << 0)
+#define ERC32_MEC_UART_STATUS_TXEA (ERC32_MEC_UART_STATUS_TXE << 0)
+
+#define ERC32_MEC_UART_STATUS_DRB (ERC32_MEC_UART_STATUS_DR << 16)
+#define ERC32_MEC_UART_STATUS_TSEB (ERC32_MEC_UART_STATUS_TSE << 16)
+#define ERC32_MEC_UART_STATUS_THEB (ERC32_MEC_UART_STATUS_THE << 16)
+#define ERC32_MEC_UART_STATUS_FEB (ERC32_MEC_UART_STATUS_FE << 16)
+#define ERC32_MEC_UART_STATUS_PEB (ERC32_MEC_UART_STATUS_PE << 16)
+#define ERC32_MEC_UART_STATUS_OEB (ERC32_MEC_UART_STATUS_OE << 16)
+#define ERC32_MEC_UART_STATUS_CUB (ERC32_MEC_UART_STATUS_CU << 16)
+#define ERC32_MEC_UART_STATUS_TXEB (ERC32_MEC_UART_STATUS_TXE << 16)
+
+#ifndef ASM
+
+/*
+ * This is used to manipulate the on-chip registers.
+ *
+ * The following symbol must be defined in the linkcmds file and point
+ * to the correct location.
+ */
+
+extern ERC32_Register_Map ERC32_MEC;
+
+/*
+ * Macros to manipulate the Interrupt Clear, Interrupt Force, Interrupt Mask,
+ * and the Interrupt Pending Registers.
+ *
+ * NOTE: For operations which are not atomic, this code disables interrupts
+ * to guarantee there are no intervening accesses to the same register.
+ * The operations which read the register, modify the value and then
+ * store the result back are vulnerable.
+ */
+
+#define ERC32_Clear_interrupt( _source ) \
+ do { \
+ ERC32_MEC.Interrupt_Clear = (1 << (_source)); \
+ } while (0)
+
+#define ERC32_Force_interrupt( _source ) \
+ do { \
+ ERC32_MEC.Interrupt_Force = (1 << (_source)); \
+ } while (0)
+
+#define ERC32_Is_interrupt_pending( _source ) \
+ (ERC32_MEC.Interrupt_Pending & (1 << (_source)))
+
+#define ERC32_Is_interrupt_masked( _source ) \
+ (ERC32_MEC.Interrupt_Masked & (1 << (_source)))
+
+#define ERC32_Mask_interrupt( _source ) \
+ do { \
+ unsigned32 _level; \
+ \
+ sparc_disable_interrupts( _level ); \
+ ERC32_MEC.Interrupt_Mask |= (1 << (_source)); \
+ sparc_enable_interrupts( _level ); \
+ } while (0)
+
+#define ERC32_Unmask_interrupt( _source ) \
+ do { \
+ unsigned32 _level; \
+ \
+ sparc_disable_interrupts( _level ); \
+ ERC32_MEC.Interrupt_Mask &= ~(1 << (_source)); \
+ sparc_enable_interrupts( _level ); \
+ } while (0)
+
+#define ERC32_Disable_interrupt( _source, _previous ) \
+ do { \
+ unsigned32 _level; \
+ unsigned32 _mask = 1 << (_source); \
+ \
+ sparc_disable_interrupts( _level ); \
+ (_previous) = ERC32_MEC.Interrupt_Mask; \
+ ERC32_MEC.Interrupt_Mask = _previous | _mask; \
+ sparc_enable_interrupts( _level ); \
+ (_previous) &= ~_mask; \
+ } while (0)
+
+#define ERC32_Restore_interrupt( _source, _previous ) \
+ do { \
+ unsigned32 _level; \
+ unsigned32 _mask = 1 << (_source); \
+ \
+ sparc_disable_interrupts( _level ); \
+ ERC32_MEC.Interrupt_Mask = \
+ (ERC32_MEC.Interrupt_Mask & ~_mask) | (_previous); \
+ sparc_enable_interrupts( _level ); \
+ } while (0)
+
+/*
+ * The following macros attempt to hide the fact that the General Purpose
+ * Timer and Real Time Clock Timer share the Timer Control Register. Because
+ * the Timer Control Register is write only, we must mirror it in software
+ * and insure that writes to one timer do not alter the current settings
+ * and status of the other timer.
+ *
+ * This code promotes the view that the two timers are completely independent.
+ * By exclusively using the routines below to access the Timer Control
+ * Register, the application can view the system as having a General Purpose
+ * Timer Control Register and a Real Time Clock Timer Control Register
+ * rather than the single shared value.
+ *
+ * Each logical timer control register is organized as follows:
+ *
+ * D0 - Counter Reload
+ * 1 = reload counter at zero and restart
+ * 0 = stop counter at zero
+ *
+ * D1 - Counter Load
+ * 1 = load counter with preset value and restart
+ * 0 = no function
+ *
+ * D2 - Enable
+ * 1 = enable counting
+ * 0 = hold scaler and counter
+ *
+ * D2 - Scaler Load
+ * 1 = load scalar with preset value and restart
+ * 0 = no function
+ *
+ * To insure the management of the mirror is atomic, we disable interrupts
+ * around updates.
+ */
+
+#define ERC32_MEC_TIMER_COUNTER_RELOAD_AT_ZERO 0x00000001
+#define ERC32_MEC_TIMER_COUNTER_STOP_AT_ZERO 0x00000000
+
+#define ERC32_MEC_TIMER_COUNTER_LOAD_COUNTER 0x00000002
+
+#define ERC32_MEC_TIMER_COUNTER_ENABLE_COUNTING 0x00000004
+#define ERC32_MEC_TIMER_COUNTER_DISABLE_COUNTING 0x00000000
+
+#define ERC32_MEC_TIMER_COUNTER_LOAD_SCALER 0x00000008
+
+#define ERC32_MEC_TIMER_COUNTER_RELOAD_MASK 0x00000001
+#define ERC32_MEC_TIMER_COUNTER_ENABLE_MASK 0x00000004
+
+#define ERC32_MEC_TIMER_COUNTER_DEFINED_MASK 0x0000000F
+#define ERC32_MEC_TIMER_COUNTER_CURRENT_MODE_MASK 0x00000005
+
+extern unsigned32 _ERC32_MEC_Timer_Control_Mirror;
+
+/*
+ * This macros manipulate the General Purpose Timer portion of the
+ * Timer Control register and promote the view that there are actually
+ * two independent Timer Control Registers.
+ */
+
+#define ERC32_MEC_Set_General_Purpose_Timer_Control( _value ) \
+ do { \
+ unsigned32 _level; \
+ unsigned32 _control; \
+ unsigned32 __value; \
+ \
+ __value = ((_value) & 0x0f); \
+ sparc_disable_interrupts( _level ); \
+ _control = _ERC32_MEC_Timer_Control_Mirror; \
+ _control &= ERC32_MEC_TIMER_COUNTER_DEFINED_MASK << 8; \
+ _ERC32_MEC_Timer_Control_Mirror = _control | _value; \
+ _control &= (ERC32_MEC_TIMER_COUNTER_CURRENT_MODE_MASK << 8); \
+ _control |= __value; \
+ /* printf( "GPT 0x%x 0x%x 0x%x\n", _value, __value, _control ); */ \
+ ERC32_MEC.Timer_Control = _control; \
+ sparc_enable_interrupts( _level ); \
+ } while ( 0 )
+
+#define ERC32_MEC_Get_General_Purpose_Timer_Control( _value ) \
+ do { \
+ (_value) = _ERC32_MEC_Timer_Control_Mirror & 0xf; \
+ } while ( 0 )
+
+/*
+ * This macros manipulate the Real Timer Clock Timer portion of the
+ * Timer Control register and promote the view that there are actually
+ * two independent Timer Control Registers.
+ */
+
+#define ERC32_MEC_Set_Real_Time_Clock_Timer_Control( _value ) \
+ do { \
+ unsigned32 _level; \
+ unsigned32 _control; \
+ unsigned32 __value; \
+ \
+ __value = ((_value) & 0x0f) << 8; \
+ sparc_disable_interrupts( _level ); \
+ _control = _ERC32_MEC_Timer_Control_Mirror; \
+ _control &= ERC32_MEC_TIMER_COUNTER_DEFINED_MASK; \
+ _ERC32_MEC_Timer_Control_Mirror = _control | _value; \
+ _control &= ERC32_MEC_TIMER_COUNTER_CURRENT_MODE_MASK; \
+ _control |= __value; \
+ /* printf( "RTC 0x%x 0x%x 0x%x\n", _value, __value, _control ); */ \
+ ERC32_MEC.Timer_Control = _control; \
+ sparc_enable_interrupts( _level ); \
+ } while ( 0 )
+
+#define ERC32_MEC_Get_Real_Time_Clock_Timer_Control( _value ) \
+ do { \
+ (_value) = _ERC32_MEC_Timer_Control_Mirror & 0xf; \
+ } while ( 0 )
+
+
+#endif /* !ASM */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_INCLUDE_ERC32_h */
+/* end of include file */
+
diff --git a/c/src/exec/score/cpu/sparc/rtems.s b/c/src/exec/score/cpu/sparc/rtems.s
index 2b9bd10454..75aa41f83b 100644
--- a/c/src/exec/score/cpu/sparc/rtems.s
+++ b/c/src/exec/score/cpu/sparc/rtems.s
@@ -22,12 +22,22 @@
* is used to look up the directive.
*
* void RTEMS()
- * {
- * }
*/
.align 4
PUBLIC(RTEMS)
SYM(RTEMS):
- ret
+ /*
+ * g2 was chosen because gcc uses it as a scratch register in
+ * similar code scenarios and the other locals, ins, and outs
+ * are off limits to this routine unless it does a "save" and
+ * copies its in registers to the outs which only works up until
+ * 6 parameters. Best to take the simple approach in this case.
+ */
+ sethi SYM(_Entry_points), %g2
+ or %g2, %lo(SYM(_Entry_points)), %g2
+ sll %g1, 2, %g1
+ add %g1, %g2, %g2
+ jmp %g2
+ nop
diff --git a/c/src/exec/score/cpu/sparc/sparc.h b/c/src/exec/score/cpu/sparc/sparc.h
index 3c5f0574f5..d6f263643b 100644
--- a/c/src/exec/score/cpu/sparc/sparc.h
+++ b/c/src/exec/score/cpu/sparc/sparc.h
@@ -1,7 +1,7 @@
/* sparc.h
*
- * This include file contains information pertaining to the Motorola
- * SPARC processor family.
+ * This include file contains information pertaining to the SPARC
+ * processor family.
*
* $Id$
*/
@@ -37,8 +37,7 @@ extern "C" {
/*
* This file contains the information required to build
- * RTEMS for a particular member of the "sparc"
- * family when executing in protected mode. It does
+ * RTEMS for a particular member of the "sparc" family. It does
* this by setting variables to indicate which implementation
* dependent features are present in a particular member
* of the family.
@@ -51,15 +50,25 @@ extern "C" {
*
* + SPARC_HAS_BITSCAN
* 0 - does not have scan instructions
- * 1 - has scan instruction (no support implemented)
+ * 1 - has scan instruction (not currently implemented)
*
+ * + SPARC_NUMBER_OF_REGISTER_WINDOWS
+ * 8 is the most common number supported by SPARC implementations.
+ * SPARC_PSR_CWP_MASK is derived from this value.
+ *
+ * + SPARC_HAS_LOW_POWER_MODE
+ * 0 - does not have low power mode support (or not supported)
+ * 1 - has low power mode and thus a CPU model dependent idle task.
+ *
*/
#if defined(erc32)
-#define CPU_MODEL_NAME "erc32"
-#define SPARC_HAS_FPU 1
-#define SPARC_HAS_BITSCAN 0
+#define CPU_MODEL_NAME "erc32"
+#define SPARC_HAS_FPU 1
+#define SPARC_HAS_BITSCAN 0
+#define SPARC_NUMBER_OF_REGISTER_WINDOWS 8
+#define SPARC_HAS_LOW_POWER_MODE 1
#else
@@ -74,6 +83,49 @@ extern "C" {
#define CPU_NAME "SPARC"
/*
+ * Miscellaneous constants
+ */
+
+/*
+ * PSR masks and starting bit positions
+ *
+ * NOTE: Reserved bits are ignored.
+ */
+
+#if (SPARC_NUMBER_OF_REGISTER_WINDOWS == 8)
+#define SPARC_PSR_CWP_MASK 0x07 /* bits 0 - 4 */
+#elif (SPARC_NUMBER_OF_REGISTER_WINDOWS == 16)
+#define SPARC_PSR_CWP_MASK 0x0F /* bits 0 - 4 */
+#elif (SPARC_NUMBER_OF_REGISTER_WINDOWS == 32)
+#define SPARC_PSR_CWP_MASK 0x1F /* bits 0 - 4 */
+#else
+#error "Unsupported number of register windows for this cpu"
+#endif
+
+#define SPARC_PSR_ET_MASK 0x00000020 /* bit 5 */
+#define SPARC_PSR_PS_MASK 0x00000040 /* bit 6 */
+#define SPARC_PSR_S_MASK 0x00000080 /* bit 7 */
+#define SPARC_PSR_PIL_MASK 0x00000F00 /* bits 8 - 11 */
+#define SPARC_PSR_EF_MASK 0x00001000 /* bit 12 */
+#define SPARC_PSR_EC_MASK 0x00002000 /* bit 13 */
+#define SPARC_PSR_ICC_MASK 0x00F00000 /* bits 20 - 23 */
+#define SPARC_PSR_VER_MASK 0x0F000000 /* bits 24 - 27 */
+#define SPARC_PSR_IMPL_MASK 0xF0000000 /* bits 28 - 31 */
+
+#define SPARC_PSR_CWP_BIT_POSITION 0 /* bits 0 - 4 */
+#define SPARC_PSR_ET_BIT_POSITION 5 /* bit 5 */
+#define SPARC_PSR_PS_BIT_POSITION 6 /* bit 6 */
+#define SPARC_PSR_S_BIT_POSITION 7 /* bit 7 */
+#define SPARC_PSR_PIL_BIT_POSITION 8 /* bits 8 - 11 */
+#define SPARC_PSR_EF_BIT_POSITION 12 /* bit 12 */
+#define SPARC_PSR_EC_BIT_POSITION 13 /* bit 13 */
+#define SPARC_PSR_ICC_BIT_POSITION 20 /* bits 20 - 23 */
+#define SPARC_PSR_VER_BIT_POSITION 24 /* bits 24 - 27 */
+#define SPARC_PSR_IMPL_BIT_POSITION 28 /* bits 28 - 31 */
+
+#ifndef ASM
+
+/*
* Standard nop
*/
@@ -83,7 +135,7 @@ extern "C" {
} while ( 0 )
/*
- * Some macros to aid in accessing special registers.
+ * Get and set the PSR
*/
#define sparc_get_psr( _psr ) \
@@ -94,26 +146,56 @@ extern "C" {
#define sparc_set_psr( _psr ) \
do { \
- asm volatile ( "wr %%g0,%0,%%psr " : "=r" ((_psr)) : "0" ((_psr)) ); \
- nop(); nop(); nop(); \
+ asm volatile ( "mov %0, %%psr " : "=r" ((_psr)) : "0" ((_psr)) ); \
+ nop(); \
+ nop(); \
+ nop(); \
} while ( 0 )
+/*
+ * Get and set the TBR
+ */
+
#define sparc_get_tbr( _tbr ) \
do { \
+ (_tbr) = 0; /* to avoid unitialized warnings */ \
asm volatile( "rd %%tbr, %0" : "=r" (_tbr) : "0" (_tbr) ); \
} while ( 0 )
#define sparc_set_tbr( _tbr ) \
do { \
+ asm volatile( "wr %0, 0, %%tbr" : "=r" (_tbr) : "0" (_tbr) ); \
} while ( 0 )
+/*
+ * Get and set the WIM
+ */
+
#define sparc_get_wim( _wim ) \
do { \
- asm volatile( "rd %%wim, %0" : "=r" (_wim) : "0" (_wim) ); \
+ asm volatile( "rd %%wim, %0" : "=r" (_wim) : "0" (_wim) ); \
} while ( 0 )
#define sparc_set_wim( _wim ) \
do { \
+ asm volatile( "wr %0, %%wim" : "=r" (_wim) : "0" (_wim) ); \
+ nop(); \
+ nop(); \
+ nop(); \
+ } while ( 0 )
+
+/*
+ * Get and set the Y
+ */
+
+#define sparc_get_y( _y ) \
+ do { \
+ asm volatile( "rd %%y, %0" : "=r" (_y) : "0" (_y) ); \
+ } while ( 0 )
+
+#define sparc_set_y( _y ) \
+ do { \
+ asm volatile( "wr %0, %%y" : "=r" (_y) : "0" (_y) ); \
} while ( 0 )
/*
@@ -121,42 +203,41 @@ extern "C" {
*
*/
-#define SPARC_PIL_MASK 0x00000F00
-
#define sparc_disable_interrupts( _level ) \
- do { register unsigned int _mask = SPARC_PIL_MASK; \
- (_level) = 0; \
+ do { \
+ register unsigned int _newlevel; \
\
- asm volatile ( "rd %%psr,%0 ; \
- wr %0,%1,%%psr " \
- : "=r" ((_level)), "=r" (_mask) \
- : "0" ((_level)), "1" (_mask) \
- ); \
- nop(); nop(); nop(); \
+ sparc_get_psr( _level ); \
+ (_newlevel) = (_level) | SPARC_PSR_PIL_MASK; \
+ sparc_set_psr( _newlevel ); \
} while ( 0 )
#define sparc_enable_interrupts( _level ) \
- do { unsigned int _tmp; \
+ do { \
+ unsigned int _tmp; \
+ \
sparc_get_psr( _tmp ); \
- _tmp &= ~SPARC_PIL_MASK; \
- _tmp |= (_level) & SPARC_PIL_MASK; \
+ _tmp &= ~SPARC_PSR_PIL_MASK; \
+ _tmp |= (_level) & SPARC_PSR_PIL_MASK; \
sparc_set_psr( _tmp ); \
} while ( 0 )
-
#define sparc_flash_interrupts( _level ) \
do { \
- register unsigned32 _ignored = 0; \
- sparc_enable_interrupts( (_level) ); \
- sparc_disable_interrupts( _ignored ); \
+ register unsigned32 _ignored = 0; \
+ \
+ sparc_enable_interrupts( (_level) ); \
+ sparc_disable_interrupts( _ignored ); \
} while ( 0 )
#define sparc_set_interrupt_level( _new_level ) \
- do { register unsigned32 _new_psr_level = 0; \
+ do { \
+ register unsigned32 _new_psr_level = 0; \
\
sparc_get_psr( _new_psr_level ); \
- _new_psr_level &= ~SPARC_PIL_MASK; \
- _new_psr_level |= (((_new_level) << 8) & SPARC_PIL_MASK); \
+ _new_psr_level &= ~SPARC_PSR_PIL_MASK; \
+ _new_psr_level |= \
+ (((_new_level) << SPARC_PSR_PIL_BIT_POSITION) & SPARC_PSR_PIL_MASK); \
sparc_set_psr( _new_psr_level ); \
} while ( 0 )
@@ -165,9 +246,12 @@ extern "C" {
register unsigned32 _psr_level = 0; \
\
sparc_get_psr( _psr_level ); \
- (_level) = (_psr_level & SPARC_PIL_MASK) >> 8; \
+ (_level) = \
+ (_psr_level & SPARC_PSR_PIL_MASK) >> SPARC_PSR_PIL_BIT_POSITION; \
} while ( 0 )
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/c/src/exec/score/cpu/sparc/sparctypes.h b/c/src/exec/score/cpu/sparc/sparctypes.h
index d07501f483..13aeb2473e 100644
--- a/c/src/exec/score/cpu/sparc/sparctypes.h
+++ b/c/src/exec/score/cpu/sparc/sparctypes.h
@@ -1,6 +1,6 @@
/* sparctypes.h
*
- * This include file contains type definitions pertaining to the Intel
+ * This include file contains type definitions pertaining to the
* SPARC processor family.
*
* $Id$
@@ -19,22 +19,22 @@ extern "C" {
* This section defines the basic types for this processor.
*/
-typedef unsigned char unsigned8; /* unsigned 8-bit integer */
-typedef unsigned short unsigned16; /* unsigned 16-bit integer */
-typedef unsigned int unsigned32; /* unsigned 32-bit integer */
-typedef unsigned long long unsigned64; /* unsigned 64-bit integer */
+typedef unsigned char unsigned8; /* unsigned 8-bit integer */
+typedef unsigned short unsigned16; /* unsigned 16-bit integer */
+typedef unsigned int unsigned32; /* unsigned 32-bit integer */
+typedef unsigned long long unsigned64; /* unsigned 64-bit integer */
-typedef unsigned16 Priority_Bit_map_control;
+typedef unsigned16 Priority_Bit_map_control;
-typedef signed char signed8; /* 8-bit signed integer */
-typedef signed short signed16; /* 16-bit signed integer */
-typedef signed int signed32; /* 32-bit signed integer */
-typedef signed long long signed64; /* 64 bit signed integer */
+typedef signed char signed8; /* 8-bit signed integer */
+typedef signed short signed16; /* 16-bit signed integer */
+typedef signed int signed32; /* 32-bit signed integer */
+typedef signed long long signed64; /* 64 bit signed integer */
-typedef unsigned32 boolean; /* Boolean value */
+typedef unsigned32 boolean; /* Boolean value */
-typedef float single_precision; /* single precision float */
-typedef double double_precision; /* double precision float */
+typedef float single_precision; /* single precision float */
+typedef double double_precision; /* double precision float */
typedef void sparc_isr;
typedef void ( *sparc_isr_entry )( void );