2009-11-09 Till Straumann <strauman@slac.stanford.edu>

* cpu.c, cpu_asm.S, rtems/score/cpu.h, sse_test.c:
	Added experimental SSE support.
This commit is contained in:
Till Straumann
2009-11-10 06:55:28 +00:00
parent 4a4201cb41
commit b02f4cc11f
4 changed files with 1134 additions and 1 deletions
+33
View File
@@ -56,9 +56,36 @@ void _CPU_Initialize(void)
fp_context = &_CPU_Null_fp_context;
#ifdef __SSE__
asm volatile( "fstcw %0":"=m"(fp_context->fpucw) );
#else
asm volatile( "fsave (%0)" : "=r" (fp_context)
: "0" (fp_context)
);
#endif
}
#endif
#ifdef __SSE__
asm volatile("stmxcsr %0":"=m"(fp_context->mxcsr));
/* The BSP must enable the SSE extensions (early).
* If any SSE instruction was already attempted
* then that crashed the system.
* As a courtesy, we double-check here but it
* may be too late (which is also why we don't
* enable SSE here).
*/
{
uint32_t cr4;
__asm__ __volatile__("mov %%cr4, %0":"=r"(cr4));
if ( 0x600 != (cr4 & 0x600) ) {
printk("PANIC: RTEMS was compiled for SSE but BSP did not enable it (CR4: 0x%08x)\n", cr4);
while ( 1 ) {
__asm__ __volatile__("hlt");
}
}
}
#endif
}
@@ -165,6 +192,9 @@ extern void rtems_exception_prologue_14(void);
extern void rtems_exception_prologue_16(void);
extern void rtems_exception_prologue_17(void);
extern void rtems_exception_prologue_18(void);
#ifdef __SSE__
extern void rtems_exception_prologue_19(void);
#endif
static rtems_raw_irq_hdl tbl[] = {
rtems_exception_prologue_0,
@@ -186,6 +216,9 @@ static rtems_raw_irq_hdl tbl[] = {
rtems_exception_prologue_16,
rtems_exception_prologue_17,
rtems_exception_prologue_18,
#ifdef __SSE__
rtems_exception_prologue_19,
#endif
};
void rtems_exception_init_mngt(void)
+34
View File
@@ -97,6 +97,7 @@ SYM (_CPU_Context_restore):
.set FPCONTEXT_ARG, 4 /* FP context argument */
#ifndef __SSE__
.p2align 1
PUBLIC (_CPU_Context_save_fp)
SYM (_CPU_Context_save_fp):
@@ -112,18 +113,44 @@ SYM (_CPU_Context_restore_fp):
movl (eax),eax /* eax = FP context area */
frstor (eax) /* restore FP context */
ret
#endif
#ifdef __SSE__
#define SSE_OFF 16
#endif
PUBLIC (_Exception_Handler)
SYM (_Exception_Handler):
pusha /* Push general purpose registers */
pushl $0 /* Null pointer to SSE area */
movl esp, ebp /* Save original SP */
#ifndef __SSE__
subl $4, esp /* Reserve space for argument */
/* Align stack (courtesy for C/gcc) */
andl $ - CPU_STACK_ALIGNMENT, esp
#else
subl $512, esp /* Space for SSE area */
/* Align stack (courtesy for C/gcc) */
andl $ - CPU_STACK_ALIGNMENT, esp
/* Doing fwait here will re-throw an already pending FP exception!
fwait
*/
fxsave 0(esp)
fninit /* Clean-slate FPU */
movl $0x1f80, 0(ebp)
ldmxcsr 0(ebp) /* Clean-slate MXCSR */
movl esp, 0(ebp) /* Store pointer to SSE area */
subl $SSE_OFF, esp /* Aligned space for argument */
#endif
movl ebp, (esp) /* Store argument */
movl _currentExcHandler, eax /* Call function stored in _currentExcHandler */
call * eax
#ifdef __SSE__
fwait
fxrstor 16(esp)
#endif
movl ebp, esp /* Restore original SP */
addl $4, esp /* Skill pointer to SSE area */
popa /* Restore general purpose registers */
addl $8, esp /* Skill vector number and faultCode */
iret
@@ -216,6 +243,13 @@ DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (17)
*/
DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (18)
#ifdef __SSE__
/*
* SIMD FP Exception
*/
DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (19)
#endif
/*
* void *i386_Logical_to_physical(
+116 -1
View File
@@ -61,6 +61,15 @@ extern "C" {
* for the i386, others have it built in (i486DX, Pentium).
*/
#ifdef __SSE__
#define CPU_HARDWARE_FP TRUE
#define CPU_SOFTWARE_FP FALSE
#define CPU_ALL_TASKS_ARE_FP TRUE
#define CPU_IDLE_TASK_IS_FP TRUE
#define CPU_USE_DEFERRED_FP_SWITCH FALSE
#else /* __SSE__ */
#if ( I386_HAS_FPU == 1 )
#define CPU_HARDWARE_FP TRUE /* i387 for i386 */
#else
@@ -71,6 +80,7 @@ extern "C" {
#define CPU_ALL_TASKS_ARE_FP FALSE
#define CPU_IDLE_TASK_IS_FP FALSE
#define CPU_USE_DEFERRED_FP_SWITCH TRUE
#endif /* __SSE__ */
#define CPU_STACK_GROWS_UP FALSE
#define CPU_STRUCTURE_ALIGNMENT
@@ -119,12 +129,38 @@ typedef struct {
/*
* FP context save area for the i387 numeric coprocessors.
*/
#ifdef __SSE__
/* All FPU and SSE registers are volatile; hence, as long
* as we are within normally executing C code (including
* a task switch) there is no need for saving/restoring
* any of those registers.
* We must save/restore the full FPU/SSE context across
* interrupts and exceptions, however:
* - after ISR execution a _Thread_Dispatch() may happen
* and it is therefore necessary to save the FPU/SSE
* registers to be restored when control is returned
* to the interrupted task.
* - gcc may implicitly use FPU/SSE instructions in
* an ISR.
*
* Even though there is no explicit mentioning of the FPU
* control word in the SYSV ABI (i386) being non-volatile
* we maintain MXCSR and the FPU control-word for each task.
*/
typedef struct {
uint32_t mxcsr;
uint16_t fpucw;
} Context_Control_fp;
#else
typedef struct {
uint8_t fp_save_area[108]; /* context size area for I80387 */
/* 28 bytes for environment */
} Context_Control_fp;
#endif
/*
* The following structure defines the set of information saved
@@ -132,9 +168,20 @@ typedef struct {
*
* idtIndex is either the interrupt number or the trap/exception number.
* faultCode is the code pushed by the processor on some exceptions.
*
* Since the first registers are directly pushed by the CPU they
* may not respect 16-byte stack alignment, which is, however,
* mandatory for the SSE register area.
* Therefore, these registers are stored at an aligned address
* and a pointer is stored in the CPU_Exception_frame.
* If the executive was compiled without SSE support then
* this pointer is NULL.
*/
struct Context_Control_sse;
typedef struct {
struct Context_Control_sse *fp_ctxt;
uint32_t edi;
uint32_t esi;
uint32_t ebp;
@@ -150,6 +197,32 @@ typedef struct {
uint32_t eflags;
} CPU_Exception_frame;
#ifdef __SSE__
typedef struct Context_Control_sse {
uint16_t fcw;
uint16_t fsw;
uint8_t ftw;
uint8_t res_1;
uint16_t fop;
uint32_t fpu_ip;
uint16_t cs;
uint16_t res_2;
uint32_t fpu_dp;
uint16_t ds;
uint16_t res_3;
uint32_t mxcsr;
uint32_t mxcsr_mask;
struct {
uint8_t fpreg[10];
uint8_t res_4[ 6];
} fp_mmregs[8];
uint8_t xmmregs[8][16];
uint8_t res_5[224];
} Context_Control_sse
__attribute__((aligned(16)))
;
#endif
typedef void (*cpuExcHandlerType) (CPU_Exception_frame*);
extern cpuExcHandlerType _currentExcHandler;
extern void rtems_exception_init_mngt(void);
@@ -510,19 +583,61 @@ void _CPU_Context_restore(
* This routine saves the floating point context passed to it.
*/
#ifdef __SSE__
#define _CPU_Context_save_fp(fp_context_pp) \
do { \
__asm__ __volatile__( \
"fstcw %0" \
:"=m"((*(fp_context_pp))->fpucw) \
); \
__asm__ __volatile__( \
"stmxcsr %0" \
:"=m"((*(fp_context_pp))->mxcsr) \
); \
} while (0)
#else
void _CPU_Context_save_fp(
Context_Control_fp **fp_context_ptr
);
#endif
/*
* _CPU_Context_restore_fp
*
* This routine restores the floating point context passed to it.
*/
#ifdef __SSE__
#define _CPU_Context_restore_fp(fp_context_pp) \
do { \
__asm__ __volatile__( \
"fldcw %0" \
::"m"((*(fp_context_pp))->fpucw) \
:"fpcr" \
); \
__builtin_ia32_ldmxcsr(_Thread_Executing->fp_context->mxcsr); \
} while (0)
#else
void _CPU_Context_restore_fp(
Context_Control_fp **fp_context_ptr
);
#endif
#ifdef __SSE__
#define _CPU_Context_Initialization_at_thread_begin() \
do { \
__asm__ __volatile__( \
"finit" \
: \
: \
:"st","st(1)","st(2)","st(3)", \
"st(4)","st(5)","st(6)","st(7)", \
"fpsr","fpcr" \
); \
if ( _Thread_Executing->fp_context ) { \
_CPU_Context_restore_fp(&_Thread_Executing->fp_context); \
} \
} while (0)
#endif
#endif /* ASM */
File diff suppressed because it is too large Load Diff