test_fp_sharing: clean up test code
Clean up test code in preparation for adding Cortex-M4 support. Change-Id: I64a32e8aa2808b4e0348601e2fc0f7f39cdb413c Signed-off-by: Peter Mitsis <peter.mitsis@windriver.com>
This commit is contained in:
parent
005925e2dd
commit
3490627a97
|
@ -1,4 +1,4 @@
|
|||
ccflags-y += -I${ZEPHYR_BASE}/tests/include
|
||||
|
||||
obj-y += main.o
|
||||
obj-y += pi.o
|
||||
obj-$(CONFIG_MICROKERNEL) += pi.o
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
/* float_context.h - common definitions for the FPU sharing test application */
|
||||
/**
|
||||
* @file
|
||||
* @brief common definitions for the FPU sharing test application
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011-2014 Wind River Systems, Inc.
|
||||
|
@ -20,10 +23,21 @@
|
|||
#define _FLOATCONTEXT_H
|
||||
|
||||
/*
|
||||
* Each architecture must define the FP_REG_SET and FP_NONVOLATILE_REG_SET
|
||||
* structures, and tailor the architecture specific implementations of
|
||||
* _LoadAllFloatRegisters(), _StoreAllFloatRegisters(), and
|
||||
* _StoreNonVolatileFloatRegisters() to read/write from these structures.
|
||||
* Each architecture must define the following structures (which may be empty):
|
||||
* 'struct fp_volatile_register_set'
|
||||
* 'struct fp_non_volatile_register_set'
|
||||
*
|
||||
* Each architecture must also define the following macros:
|
||||
* SIZEOF_FP_VOLATILE_REGISTER_SET
|
||||
* SIZEOF_FP_NON_VOLATILE_REGISTER_SET
|
||||
* Those macros are used as sizeof(<an empty structure>) is compiler specific;
|
||||
* that is, it may evaluate to a non-zero value.
|
||||
*
|
||||
* Each architecture shall also have custom implementations of:
|
||||
* _load_all_float_registers()
|
||||
* _load_then_store_all_float_registers()
|
||||
* _store_all_float_registers()
|
||||
* _store_non_volatile_float_registers()
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_ISA_IA32)
|
||||
|
@ -32,57 +46,52 @@
|
|||
|
||||
/*
|
||||
* In the future, the struct definitions may need to be refined based on the
|
||||
* specific IA-32 processor, but for now only the Pentium4 is supported.
|
||||
* specific IA-32 processor, but for now only the Pentium4 is supported:
|
||||
*
|
||||
* There exists 8 x 80 bit floating point registers (ST[0] -> ST[7]) and
|
||||
* 8 * 128 bit XMM registers (XMM[0] -> XMM[7]). All of these registers are
|
||||
* considered volatile across a function invocation.
|
||||
* 8 x 80 bit floating point registers (ST[0] -> ST[7])
|
||||
* 8 x 128 bit XMM registers (XMM[0] -> XMM[7])
|
||||
*
|
||||
* All these registers are considered volatile across a function invocation.
|
||||
*/
|
||||
|
||||
/* a single x87 FPU register in double extended format (80 bits) */
|
||||
|
||||
typedef struct fpReg {
|
||||
struct fp_register {
|
||||
unsigned char reg[10];
|
||||
} FP_REG;
|
||||
};
|
||||
|
||||
/* a single XMM register (128 bits) */
|
||||
|
||||
typedef struct xmmReg {
|
||||
struct xmm_register {
|
||||
unsigned char reg[16];
|
||||
} XMM_REG;
|
||||
};
|
||||
|
||||
/* the set of volatile floating point registers */
|
||||
struct fp_volatile_register_set {
|
||||
struct xmm_register xmm[8]; /* XMM[0] -> XMM[7] */
|
||||
struct fp_register st[8]; /* ST[0] -> ST[7] */
|
||||
};
|
||||
|
||||
typedef struct fpVolatileRegSet {
|
||||
XMM_REG xmmRegs[8]; /* XMM[0] -> XMM[7] */
|
||||
FP_REG fpRegs[8]; /* ST[0] -> ST[7] */
|
||||
} FP_VOLATILE_REG_SET;
|
||||
|
||||
/* the set of non-volatile floating point registers */
|
||||
|
||||
typedef struct fpNonVolatileRegSet {
|
||||
/* this structure has been intentionally left blank */
|
||||
} FP_NONVOLATILE_REG_SET;
|
||||
|
||||
#define SIZEOF_FP_VOLATILE_REG_SET sizeof(FP_VOLATILE_REG_SET)
|
||||
#define SIZEOF_FP_NONVOLATILE_REG_SET 0
|
||||
struct fp_non_volatile_register_set {
|
||||
/* No non-volatile floating point registers */
|
||||
};
|
||||
|
||||
#define SIZEOF_FP_VOLATILE_REGISTER_SET sizeof(struct fp_volatile_register_set)
|
||||
#define SIZEOF_FP_NON_VOLATILE_REGISTER_SET 0
|
||||
|
||||
#else /* ! CONFIG_ISA_IA32 */
|
||||
|
||||
#error Architecture needs to provide a definition for 'struct fpRegSet' \
|
||||
and 'struct fpNonVolatileRegSet'
|
||||
#error "Architecture must provide the following definitions:\n" \
|
||||
"\t'struct fp_volatile_registers'\n" \
|
||||
"\t'struct fp_non_volatile_registers'\n" \
|
||||
"\t'SIZEOF_FP_VOLATILE_REGISTER_SET'\n" \
|
||||
"\t'SIZEOF_FP_NON_VOLATILE_REGISTER_SET'\n"
|
||||
#endif /* CONFIG_ISA_IA32 */
|
||||
|
||||
/* the set of ALL floating point registers */
|
||||
|
||||
typedef struct fpRegSet {
|
||||
FP_VOLATILE_REG_SET fpVolRegSet;
|
||||
FP_NONVOLATILE_REG_SET fpNonVolRegSet;
|
||||
} FP_REG_SET;
|
||||
struct fp_register_set {
|
||||
struct fp_volatile_register_set fp_volatile;
|
||||
struct fp_non_volatile_register_set fp_non_volatile;
|
||||
};
|
||||
|
||||
#define SIZEOF_FP_REG_SET \
|
||||
(SIZEOF_FP_VOLATILE_REG_SET + SIZEOF_FP_NONVOLATILE_REG_SET)
|
||||
#define SIZEOF_FP_REGISTER_SET \
|
||||
(SIZEOF_FP_VOLATILE_REGISTER_SET + SIZEOF_FP_NON_VOLATILE_REGISTER_SET)
|
||||
|
||||
/*
|
||||
* The following constants define the initial byte value used by the background
|
||||
|
@ -92,8 +101,8 @@ typedef struct fpRegSet {
|
|||
#define MAIN_FLOAT_REG_CHECK_BYTE (unsigned char)0xe5
|
||||
#define FIBER_FLOAT_REG_CHECK_BYTE (unsigned char)0xf9
|
||||
|
||||
void _StoreNonVolatileFloatRegisters(FP_NONVOLATILE_REG_SET *pToBuffer);
|
||||
void _store_non_volatile_float_registers(struct fp_non_volatile_register_set *regs);
|
||||
|
||||
extern int fpu_sharing_error;
|
||||
|
||||
#endif /* _FLOATRCONTEXT_H */
|
||||
#endif /* _FLOATCONTEXT_H */
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
/* Intel x86 GCC specific floating point register macros */
|
||||
/**
|
||||
* @file
|
||||
* @brief Intel x86 GCC specific floating point register macros
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015, Wind River Systems, Inc.
|
||||
|
@ -20,7 +23,7 @@
|
|||
#define _FLOAT_REGS_X86_GCC_H
|
||||
|
||||
#if !defined(__GNUC__) || !defined(CONFIG_ISA_IA32)
|
||||
#error test_asm_inline_gcc.h goes only with x86 GCC
|
||||
#error __FILE__ goes only with x86 GCC
|
||||
#endif
|
||||
|
||||
#include <toolchain.h>
|
||||
|
@ -30,47 +33,22 @@
|
|||
*
|
||||
* @brief Load all floating point registers
|
||||
*
|
||||
* This function loads ALL floating point registers from the memory buffer
|
||||
* specified by <pFromBuffer>. It is expected that a subsequent call to
|
||||
* _StoreAllFloatRegisters() will be issued to dump the floating point registers
|
||||
* to memory.
|
||||
* This function loads ALL floating point registers pointed to by @a regs.
|
||||
* It is expected that a subsequent call to _store_all_float_registers()
|
||||
* will be issued to dump the floating point registers to memory.
|
||||
*
|
||||
* The format/organization of the FP_REG_SET structure is not important; the
|
||||
* generic C test code (main.c and fiber.c) merely treat the FP_REG_SET
|
||||
* (and FP_NONVOLATILE_REG_SET) as an array of bytes.
|
||||
* The format/organization of 'struct fp_register_set'; the generic C test
|
||||
* code (main.c) merely treat the register set as an array of bytes.
|
||||
*
|
||||
* The only requirement is that the arch specific implementations of
|
||||
* _LoadAllFloatRegisters(), _StoreAllFloatRegisters(), and
|
||||
* _LoadThenStoreAllFloatRegisters agree on the format.
|
||||
* _load_all_float_registers(), _store_all_float_registers() and
|
||||
* _load_then_store_all_float_registers() agree on the format.
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
|
||||
static inline void _LoadAllFloatRegisters(FP_REG_SET *pFromBuffer)
|
||||
static inline void _load_all_float_registers(struct fp_register_set *regs)
|
||||
{
|
||||
/*
|
||||
* The 'movdqu' is the "move double quad unaligned" instruction: Move
|
||||
* a double quadword (16 bytes) between memory and an XMM register (or
|
||||
* between a pair of XMM registers). The memory destination/source operand
|
||||
* may be unaligned on a 16-byte boundary without causing an exception.
|
||||
*
|
||||
* The 'fldt' is the "load floating point value" instruction: Push an 80-bit
|
||||
* (double extended-precision) onto the FPU register stack.
|
||||
*
|
||||
* A note about operand size specification in the AT&T assembler syntax:
|
||||
*
|
||||
* Instructions are generally suffixed with the a letter or a pair of
|
||||
* letters to specify the operand size:
|
||||
*
|
||||
* b = byte (8 bit)
|
||||
* s = short (16 bit integer) or single (32-bit floating point)
|
||||
* w = word (16 bit)
|
||||
* l = long (32 bit integer or 64-bit floating point)
|
||||
* q = quad (64 bit)
|
||||
* t = ten bytes (80-bit floating point)
|
||||
* dq = double quad (128 bit)
|
||||
*/
|
||||
|
||||
__asm__ volatile (
|
||||
"movdqu 0(%0), %%xmm0\n\t;"
|
||||
"movdqu 16(%0), %%xmm1\n\t;"
|
||||
|
@ -90,7 +68,7 @@ static inline void _LoadAllFloatRegisters(FP_REG_SET *pFromBuffer)
|
|||
"fldt 188(%0)\n\t;"
|
||||
"fldt 198(%0)\n\t;"
|
||||
|
||||
:: "r" (pFromBuffer)
|
||||
:: "r" (regs)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -100,7 +78,7 @@ static inline void _LoadAllFloatRegisters(FP_REG_SET *pFromBuffer)
|
|||
* @brief Load then dump all float registers to memory
|
||||
*
|
||||
* This function loads ALL floating point registers from the memory buffer
|
||||
* specified by <pFromToBuffer>, and then stores them back to that buffer.
|
||||
* specified by @a regs, and then stores them back to that buffer.
|
||||
*
|
||||
* This routine is called by a high priority thread prior to calling a primitive
|
||||
* that pends and triggers a co-operative context switch to a low priority
|
||||
|
@ -113,7 +91,7 @@ static inline void _LoadAllFloatRegisters(FP_REG_SET *pFromBuffer)
|
|||
* @return N/A
|
||||
*/
|
||||
|
||||
static inline void _LoadThenStoreAllFloatRegisters(FP_REG_SET *pFromToBuffer)
|
||||
static inline void _load_then_store_all_float_registers(struct fp_register_set *regs)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"movdqu 0(%0), %%xmm0\n\t;"
|
||||
|
@ -145,7 +123,7 @@ static inline void _LoadThenStoreAllFloatRegisters(FP_REG_SET *pFromToBuffer)
|
|||
"fstpt 138(%0)\n\t;"
|
||||
"fstpt 128(%0)\n\t;"
|
||||
|
||||
:: "r" (pFromToBuffer)
|
||||
:: "r" (regs)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -155,14 +133,14 @@ static inline void _LoadThenStoreAllFloatRegisters(FP_REG_SET *pFromToBuffer)
|
|||
* @brief Dump all floating point registers to memory
|
||||
*
|
||||
* This function stores ALL floating point registers to the memory buffer
|
||||
* specified by <pToBuffer>. It is expected that a previous invocation of
|
||||
* _LoadAllFloatRegisters() occurred to load all the floating point registers
|
||||
* from a memory buffer.
|
||||
* specified by @a regs. It is expected that a previous invocation of
|
||||
* _load_all_float_registers() occurred to load all the floating point
|
||||
* registers from a memory buffer.
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
|
||||
static inline void _StoreAllFloatRegisters(FP_REG_SET *pToBuffer)
|
||||
static inline void _store_all_float_registers(struct fp_register_set *regs)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"movdqu %%xmm0, 0(%0)\n\t;"
|
||||
|
@ -183,28 +161,7 @@ static inline void _StoreAllFloatRegisters(FP_REG_SET *pToBuffer)
|
|||
"fstpt 138(%0)\n\t;"
|
||||
"fstpt 128(%0)\n\t;"
|
||||
|
||||
:: "r" (pToBuffer) : "memory"
|
||||
:: "r" (regs) : "memory"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Dump non-volatile FP registers to memory
|
||||
*
|
||||
* This routine is called by a high priority thread after resuming execution
|
||||
* from calling a primitive that will pend and thus result in a co-operative
|
||||
* context switch to a low priority thread.
|
||||
*
|
||||
* Only the non-volatile floating point registers are expected to survive across
|
||||
* a function call, regardless of whether the call results in the thread being
|
||||
* pended.
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
|
||||
void _StoreNonVolatileFloatRegisters(FP_NONVOLATILE_REG_SET *pToBuffer)
|
||||
{
|
||||
ARG_UNUSED(pToBuffer);
|
||||
/* do nothing; there are no non-volatile floating point registers */
|
||||
}
|
||||
#endif /* _FLOAT_REGS_X86_GCC_H */
|
||||
|
|
|
@ -23,9 +23,8 @@ microkernel version of this test utilizes a pair of tasks, while the nanokernel
|
|||
verions utilizes a task and a fiber.
|
||||
|
||||
The load/store test validates the nanokernel's floating point unit context
|
||||
save/restore mechanism. (For the IA-32 architecture this includes the x87 FPU
|
||||
(MMX) registers and the XMM registers.) This test utilizes a pair of threads
|
||||
of different priorities that each use the floating point registers. The context
|
||||
save/restore mechanism. This test utilizes a pair of threads of different
|
||||
priorities that each use the floating point registers. The context
|
||||
switching that occurs exercises the kernel's ability to properly preserve the
|
||||
floating point registers. The test also exercises the kernel's ability to
|
||||
automatically enable floating point support for a task, if supported.
|
||||
|
@ -36,28 +35,26 @@ for example on IA-32 the USE_FP and USE_SSE options are provided, this test
|
|||
should be enhanced to ensure that the architectures' _Swap() routine doesn't
|
||||
context switch more registers that it needs to (which would represent a
|
||||
performance issue). For example, on the IA-32, the test should issue
|
||||
a nanoCpuFpDisable() from main(), and then indicate that only x87 FPU
|
||||
registers will be utilized (nanoCpuFpEnable). The fiber should continue
|
||||
a fiber_fp_disable() from main(), and then indicate that only x87 FPU
|
||||
registers will be utilized (fiber_fp_enable()). The fiber should continue
|
||||
to load ALL non-integer registers, but main() should validate that only the
|
||||
x87 FPU registers are being saved/restored.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_ISA_IA32)
|
||||
#ifndef CONFIG_FLOAT
|
||||
#error Rebuild the nanokernel with the FLOAT config option enabled
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SSE
|
||||
#error Rebuild the nanokernel with the SSE config option enabled
|
||||
#error Rebuild with the FLOAT config option enabled
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_FP_SHARING
|
||||
#error Rebuild the nanokernel with the FP_SHARING config option enabled
|
||||
#error Rebuild with the FP_SHARING config option enabled
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ISA_IA32)
|
||||
#ifndef CONFIG_SSE
|
||||
#error Rebuild with the SSE config option enabled
|
||||
#endif
|
||||
#endif /* CONFIG_ISA_IA32 */
|
||||
|
||||
|
||||
#include <zephyr.h>
|
||||
|
||||
#if defined(__GNUC__)
|
||||
|
@ -72,32 +69,25 @@ x87 FPU registers are being saved/restored.
|
|||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef MAX_TESTS
|
||||
/* test duration, unless overridden by project builder (0 => run forever) */
|
||||
#define MAX_TESTS 500
|
||||
#endif
|
||||
|
||||
/* macro used to read system clock value */
|
||||
|
||||
#define TICK_COUNT_GET() sys_tick_get_32()
|
||||
|
||||
/* space for float register load/store area used by low priority task */
|
||||
|
||||
static FP_REG_SET floatRegSetLoad;
|
||||
static FP_REG_SET floatRegSetStore;
|
||||
static struct fp_register_set float_reg_set_load;
|
||||
static struct fp_register_set float_reg_set_store;
|
||||
|
||||
/* space for float register load/store area used by high priority thread */
|
||||
|
||||
static FP_REG_SET floatRegisterSet;
|
||||
static struct fp_register_set float_reg_set;
|
||||
|
||||
|
||||
#ifdef CONFIG_NANOKERNEL
|
||||
/* stack for high priority fiber (also use .bss for floatRegisterSet) */
|
||||
/* stack for high priority fiber (also use .bss for float_reg_set) */
|
||||
|
||||
static char __stack fiberStack[1024];
|
||||
static char __stack fiber_stack[1024];
|
||||
|
||||
static struct nano_timer fiberTimer;
|
||||
static void *dummyTimerData; /* allocate just enough room for a pointer */
|
||||
static struct nano_timer fiber_timer;
|
||||
static void *dummy_timer_data; /* allocate just enough room for a pointer */
|
||||
#endif
|
||||
|
||||
/* flag indicating that an error has occurred */
|
||||
|
@ -112,9 +102,12 @@ int fpu_sharing_error;
|
|||
static volatile unsigned int load_store_low_count = 0;
|
||||
static volatile unsigned int load_store_high_count = 0;
|
||||
|
||||
#ifdef CONFIG_NANOKERNEL
|
||||
static void load_store_high(int, int);
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* main -
|
||||
* @brief Low priority FPU load/store thread
|
||||
*
|
||||
* @return N/A
|
||||
|
@ -126,26 +119,16 @@ void main(void)
|
|||
void load_store_low(void)
|
||||
#endif
|
||||
{
|
||||
unsigned int bufIx;
|
||||
unsigned char floatRegInitByte;
|
||||
unsigned char *floatRegSetStorePtr = (unsigned char *)&floatRegSetStore;
|
||||
unsigned int i;
|
||||
unsigned char init_byte;
|
||||
unsigned char *store_ptr = (unsigned char *)&float_reg_set_store;
|
||||
unsigned char *load_ptr = (unsigned char *)&float_reg_set_load;
|
||||
|
||||
volatile char volatileStackVar;
|
||||
volatile char volatile_stack_var;
|
||||
|
||||
PRINT_DATA("Floating point sharing tests started\n");
|
||||
PRINT_LINE;
|
||||
|
||||
#if defined(CONFIG_FP_SHARING)
|
||||
/*
|
||||
* No need to invoke task_float_enable() since
|
||||
* FP_SHARING is in effect
|
||||
*/
|
||||
#else /* ! CONFIG_FP_SHARING */
|
||||
#if defined(CONFIG_FLOAT)
|
||||
task_float_enable(sys_thread_self_get());
|
||||
#endif
|
||||
#endif /* CONFIG_FP_SHARING */
|
||||
|
||||
#ifdef CONFIG_NANOKERNEL
|
||||
/*
|
||||
* Start a single fiber which will regularly preempt the background
|
||||
|
@ -154,10 +137,8 @@ void load_store_low(void)
|
|||
* is loaded into the floating point registers.
|
||||
*/
|
||||
|
||||
extern void load_store_high(int regFillValue, int unused);
|
||||
|
||||
task_fiber_start(fiberStack,
|
||||
sizeof(fiberStack),
|
||||
task_fiber_start(fiber_stack,
|
||||
sizeof(fiber_stack),
|
||||
load_store_high,
|
||||
0, /* arg1 */
|
||||
0, /* arg2 */
|
||||
|
@ -166,7 +147,8 @@ void load_store_low(void)
|
|||
);
|
||||
#elif defined(CONFIG_MICROKERNEL)
|
||||
/*
|
||||
* For microkernel builds, preemption tasks are specified in the .mdef file.
|
||||
* For microkernel builds, preemption tasks are specified in the .mdef
|
||||
* file.
|
||||
*
|
||||
* Enable round robin scheduling to allow both the low priority pi
|
||||
* computation and load/store tasks to execute. The high priority pi
|
||||
|
@ -182,9 +164,9 @@ void load_store_low(void)
|
|||
* these values must be different than the value used in other threads.
|
||||
*/
|
||||
|
||||
floatRegInitByte = MAIN_FLOAT_REG_CHECK_BYTE;
|
||||
for (bufIx = 0; bufIx < SIZEOF_FP_REG_SET; ++bufIx) {
|
||||
((unsigned char *)&floatRegSetLoad)[bufIx] = floatRegInitByte++;
|
||||
init_byte = MAIN_FLOAT_REG_CHECK_BYTE;
|
||||
for (i = 0; i < SIZEOF_FP_REGISTER_SET; i++) {
|
||||
load_ptr[i] = init_byte++;
|
||||
}
|
||||
|
||||
/* Keep cranking forever, or until an error is detected. */
|
||||
|
@ -196,59 +178,60 @@ void load_store_low(void)
|
|||
* floating point values that have been saved.
|
||||
*/
|
||||
|
||||
memset(&floatRegSetStore, 0, SIZEOF_FP_REG_SET);
|
||||
memset(&float_reg_set_store, 0, SIZEOF_FP_REGISTER_SET);
|
||||
|
||||
/*
|
||||
* Utilize an architecture specific function to load all the floating
|
||||
* point (and XMM on IA-32) registers with known values.
|
||||
* Utilize an architecture specific function to load all the
|
||||
* floating point registers with known values.
|
||||
*/
|
||||
|
||||
_LoadAllFloatRegisters(&floatRegSetLoad);
|
||||
_load_all_float_registers(&float_reg_set_load);
|
||||
|
||||
/*
|
||||
* Waste some cycles to give the high priority load/store thread
|
||||
* an opportunity to run when the low priority thread is using the
|
||||
* floating point registers.
|
||||
* Waste some cycles to give the high priority load/store
|
||||
* thread an opportunity to run when the low priority thread is
|
||||
* using the floating point registers.
|
||||
*
|
||||
* IMPORTANT: This logic requires that TICK_COUNT_GET() not perform
|
||||
* any floating point operations!
|
||||
* IMPORTANT: This logic requires that sys_tick_get_32() not
|
||||
* perform any floating point operations!
|
||||
*/
|
||||
|
||||
while ((TICK_COUNT_GET() % 5) != 0) {
|
||||
while ((sys_tick_get_32() % 5) != 0) {
|
||||
/*
|
||||
* Use a volatile variable to prevent compiler optimizing
|
||||
* out the spin loop.
|
||||
* Use a volatile variable to prevent compiler
|
||||
* optimizing out the spin loop.
|
||||
*/
|
||||
++volatileStackVar;
|
||||
++volatile_stack_var;
|
||||
}
|
||||
|
||||
/*
|
||||
* Utilize an architecture specific function to dump the contents
|
||||
* of all floating point (and XMM on IA-32) register to memory.
|
||||
* Utilize an architecture specific function to dump the
|
||||
* contents of all floating point registers to memory.
|
||||
*/
|
||||
|
||||
_StoreAllFloatRegisters(&floatRegSetStore);
|
||||
_store_all_float_registers(&float_reg_set_store);
|
||||
|
||||
/*
|
||||
* Compare each byte of buffer to ensure the expected value is
|
||||
* present, indicating that the floating point registers weren't
|
||||
* impacted by the operation of the high priority thread(s).
|
||||
*
|
||||
* Display error message and terminate if discrepancies are detected.
|
||||
* Display error message and terminate if discrepancies are
|
||||
* detected.
|
||||
*/
|
||||
|
||||
floatRegInitByte = MAIN_FLOAT_REG_CHECK_BYTE;
|
||||
init_byte = MAIN_FLOAT_REG_CHECK_BYTE;
|
||||
|
||||
for (bufIx = 0; bufIx < SIZEOF_FP_REG_SET; ++bufIx) {
|
||||
if (floatRegSetStorePtr[bufIx] != floatRegInitByte) {
|
||||
TC_ERROR("load_store_low found 0x%x instead of 0x%x"
|
||||
" @ offset 0x%x\n",
|
||||
floatRegSetStorePtr[bufIx], floatRegInitByte, bufIx);
|
||||
for (i = 0; i < SIZEOF_FP_REGISTER_SET; i++) {
|
||||
if (store_ptr[i] != init_byte) {
|
||||
TC_ERROR("load_store_low found 0x%x instead of 0x%x @ offset 0x%x\n",
|
||||
store_ptr[i],
|
||||
init_byte, i);
|
||||
TC_ERROR("Discrepancy found during iteration %d\n",
|
||||
load_store_low_count);
|
||||
load_store_low_count);
|
||||
fpu_sharing_error = 1;
|
||||
}
|
||||
floatRegInitByte++;
|
||||
init_byte++;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -261,23 +244,20 @@ void load_store_low(void)
|
|||
return;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FP_SHARING)
|
||||
/*
|
||||
* After every 1000 iterations (arbitrarily chosen), explicitly
|
||||
* disable floating point operations for the task. The subsequent
|
||||
* execution of _LoadAllFloatRegisters() will result in an exception
|
||||
* to automatically re-enable floating point support for the task.
|
||||
* disable floating point operations for the task. The
|
||||
* subsequent execution of _load_all_float_registers() will result
|
||||
* in an exception to automatically re-enable floating point
|
||||
* support for the task.
|
||||
*
|
||||
* The purpose of this part of the test is to exercise the
|
||||
* task_float_disable() API, and to also continue exercising the
|
||||
* (exception based) floating enabling mechanism.
|
||||
* task_float_disable() API, and to also continue exercising
|
||||
* the (exception based) floating enabling mechanism.
|
||||
*/
|
||||
if ((load_store_low_count % 1000) == 0) {
|
||||
#if defined(CONFIG_FLOAT)
|
||||
task_float_disable(sys_thread_self_get());
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_FP_SHARING */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,13 +274,9 @@ void load_store_high(int unused1, int unused2)
|
|||
void load_store_high(void)
|
||||
#endif
|
||||
{
|
||||
unsigned int bufIx;
|
||||
unsigned char floatRegInitByte;
|
||||
#if !defined(CONFIG_ISA_IA32)
|
||||
unsigned int numNonVolatileBytes;
|
||||
#endif /* !CONFIG_ISA_IA32 */
|
||||
unsigned char *floatRegisterSetBytePtr =
|
||||
(unsigned char *)&floatRegisterSet;
|
||||
unsigned int i;
|
||||
unsigned char init_byte;
|
||||
unsigned char *reg_set_ptr = (unsigned char *)&float_reg_set;
|
||||
|
||||
#ifdef CONFIG_NANOKERNEL
|
||||
ARG_UNUSED(unused1);
|
||||
|
@ -308,65 +284,71 @@ void load_store_high(void)
|
|||
|
||||
/* initialize timer; data field is not used */
|
||||
|
||||
nano_timer_init(&fiberTimer, (void *)dummyTimerData);
|
||||
nano_timer_init(&fiber_timer, (void *)dummy_timer_data);
|
||||
#endif
|
||||
|
||||
/* test until the specified time limit, or until an error is detected */
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* Initialize the floatRegisterSet structure by treating it as a simple
|
||||
* array of bytes (the arrangement and actual number of registers is
|
||||
* not important for this generic C code). The structure is
|
||||
* initialized by using the byte value specified by the constant
|
||||
* FIBER_FLOAT_REG_CHECK_BYTE, and then incrementing the value for each
|
||||
* successive location in the floatRegisterSet structure.
|
||||
* Initialize the float_reg_set structure by treating it as
|
||||
* a simple array of bytes (the arrangement and actual number
|
||||
* of registers is not important for this generic C code). The
|
||||
* structure is initialized by using the byte value specified
|
||||
* by the constant FIBER_FLOAT_REG_CHECK_BYTE, and then
|
||||
* incrementing the value for each successive location in the
|
||||
* float_reg_set structure.
|
||||
*
|
||||
* The initial byte value, and thus the contents of the entire
|
||||
* floatRegisterSet structure, must be different for each thread to
|
||||
* effectively test the nanokernel's ability to properly save/restore
|
||||
* the floating point values during a context switch.
|
||||
* float_reg_set structure, must be different for each
|
||||
* thread to effectively test the nanokernel's ability to
|
||||
* properly save/restore the floating point values during a
|
||||
* context switch.
|
||||
*/
|
||||
|
||||
floatRegInitByte = FIBER_FLOAT_REG_CHECK_BYTE;
|
||||
init_byte = FIBER_FLOAT_REG_CHECK_BYTE;
|
||||
|
||||
for (bufIx = 0; bufIx < SIZEOF_FP_REG_SET; ++bufIx) {
|
||||
floatRegisterSetBytePtr[bufIx] = floatRegInitByte++;
|
||||
for (i = 0; i < SIZEOF_FP_REGISTER_SET; i++) {
|
||||
reg_set_ptr[i] = init_byte++;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ISA_IA32)
|
||||
/*
|
||||
* Utilize an architecture specific function to load all the floating
|
||||
* point (and XMM on IA-32) registers with the contents of
|
||||
* the floatRegisterSet structure.
|
||||
* Utilize an architecture specific function to load all the
|
||||
* floating point registers with the contents of the
|
||||
* float_reg_set structure.
|
||||
*
|
||||
* The goal of the loading all floating point registers with values
|
||||
* that differ from the values used in other threads is to help
|
||||
* determine whether the floating point register save/restore mechanism
|
||||
* in the nanokernel's context switcher is operating correctly.
|
||||
* The goal of the loading all floating point registers with
|
||||
* values that differ from the values used in other threads is
|
||||
* to help determine whether the floating point register
|
||||
* save/restore mechanism in the nanokernel's context switcher
|
||||
* is operating correctly.
|
||||
*
|
||||
* When a subsequent nano_fiber_timer_test() invocation is performed, a
|
||||
* (cooperative) context switch back to the preempted task will occur.
|
||||
* This context switch should result in restoring the state of the
|
||||
* task's floating point registers when the task was swapped out due
|
||||
* to the occurence of the timer tick.
|
||||
* When a subsequent nano_fiber_timer_test() invocation is
|
||||
* performed, a (cooperative) context switch back to the
|
||||
* preempted task will occur. This context switch should result
|
||||
* in restoring the state of the task's floating point
|
||||
* registers when the task was swapped out due to the
|
||||
* occurrence of the timer tick.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_ISA_IA32)
|
||||
_LoadThenStoreAllFloatRegisters(&floatRegisterSet);
|
||||
_load_then_store_all_float_registers(&float_reg_set);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Relinquish the processor for the remainder of the current system
|
||||
* clock tick, so that lower priority threads get a chance to run.
|
||||
* Relinquish the processor for the remainder of the current
|
||||
* system clock tick, so that lower priority threads get a
|
||||
* chance to run.
|
||||
*
|
||||
* This exercises the ability of the nanokernel to restore the FPU
|
||||
* state of a low priority thread _and_ the ability of the nanokernel
|
||||
* to provide a "clean" FPU state to this thread once the sleep ends.
|
||||
* This exercises the ability of the nanokernel to restore the
|
||||
* FPU state of a low priority thread _and_ the ability of the
|
||||
* nanokernel to provide a "clean" FPU state to this thread
|
||||
* once the sleep ends.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NANOKERNEL
|
||||
nano_fiber_timer_start(&fiberTimer, 1);
|
||||
nano_fiber_timer_test(&fiberTimer, TICKS_UNLIMITED);
|
||||
nano_fiber_timer_start(&fiber_timer, 1);
|
||||
nano_fiber_timer_test(&fiber_timer, TICKS_UNLIMITED);
|
||||
#else
|
||||
task_sleep(1);
|
||||
#endif
|
||||
|
@ -375,10 +357,10 @@ void load_store_high(void)
|
|||
|
||||
if ((++load_store_high_count % 100) == 0) {
|
||||
PRINT_DATA("Load and store OK after %u (high) + %u (low) tests\n",
|
||||
load_store_high_count, load_store_low_count);
|
||||
load_store_high_count,
|
||||
load_store_low_count);
|
||||
}
|
||||
|
||||
#if (MAX_TESTS != 0)
|
||||
/* terminate testing if specified limit has been reached */
|
||||
|
||||
if (load_store_high_count == MAX_TESTS) {
|
||||
|
@ -386,6 +368,5 @@ void load_store_high(void)
|
|||
TC_END_REPORT(TC_PASS);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ has occurred.
|
|||
|
||||
#include <zephyr.h>
|
||||
|
||||
#ifdef CONFIG_MICROKERNEL
|
||||
#include <stdio.h>
|
||||
#include <tc_util.h>
|
||||
|
||||
|
@ -94,7 +93,7 @@ void calculate_pi_low(void)
|
|||
reference_pi = pi;
|
||||
} else if (reference_pi != pi) {
|
||||
TC_ERROR("Computed pi %1.6f, reference pi %1.6f\n",
|
||||
pi, reference_pi);
|
||||
pi, reference_pi);
|
||||
fpu_sharing_error = 1;
|
||||
return;
|
||||
}
|
||||
|
@ -132,12 +131,14 @@ void calculate_pi_high(void)
|
|||
}
|
||||
|
||||
/*
|
||||
* Relinquish the processor for the remainder of the current system
|
||||
* clock tick, so that lower priority threads get a chance to run.
|
||||
* Relinquish the processor for the remainder of the current
|
||||
* system clock tick, so that lower priority threads get a
|
||||
* chance to run.
|
||||
*
|
||||
* This exercises the ability of the nanokernel to restore the FPU
|
||||
* state of a low priority thread _and_ the ability of the nanokernel
|
||||
* to provide a "clean" FPU state to this thread once the sleep ends.
|
||||
* This exercises the ability of the nanokernel to restore the
|
||||
* FPU state of a low priority thread _and_ the ability of the
|
||||
* nanokernel to provide a "clean" FPU state to this thread
|
||||
* once the sleep ends.
|
||||
*/
|
||||
|
||||
task_sleep(1);
|
||||
|
@ -156,11 +157,8 @@ void calculate_pi_high(void)
|
|||
/* periodically issue progress report */
|
||||
|
||||
if ((++calc_pi_high_count % 100) == 50) {
|
||||
printf("Pi calculation OK after %u (high) + %u (low) tests "
|
||||
"(computed %1.6f)\n",
|
||||
calc_pi_high_count, calc_pi_low_count, pi);
|
||||
printf("Pi calculation OK after %u (high) + %u (low) tests (computed %1.6f)\n",
|
||||
calc_pi_high_count, calc_pi_low_count, pi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MICROKERNEL */
|
||||
|
|
Loading…
Reference in a new issue