mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-09-21 21:05:22 +08:00
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:
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user