changeset 3216:f35f92c0b860

Add single precision floating point tests.
author vae
date Sat, 09 Mar 2013 18:06:46 +0000
parents 568dc3bf6c43
children 10a2004b0d31
files packages/kernel/current/ChangeLog packages/kernel/current/cdl/kernel.cdl packages/kernel/current/tests/fpint_thread_switch.cxx packages/kernel/current/tests/fpinttestf.c packages/kernel/current/tests/fpinttestf1.c packages/kernel/current/tests/fpinttestf2.c
diffstat 6 files changed, 1585 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/packages/kernel/current/ChangeLog
+++ b/packages/kernel/current/ChangeLog
@@ -1,3 +1,11 @@
+2013-02-10  Ilija Kocho  <ilijak@siva.com.mk>
+            Jonathan Larmour  <jifl@eCosCentric.com>
+
+	* cdl/kernel.cdl:
+	* tests/fpinttestf.c, tests/fpinttestf1.c, tests/fpinttestf2.c,
+	* tests/fpint_thread_switch.c: Add single precision floating point tests.
+	[ Bugzilla 1001607 ]
+
 2012-10-04  Ilija Kocho <ilijak@siva.com.mk>
 
 	* tests/kcache2.c: Include CYGHWR_MEMORY_LAYOUT_H in order to
--- a/packages/kernel/current/cdl/kernel.cdl
+++ b/packages/kernel/current/cdl/kernel.cdl
@@ -151,14 +151,14 @@ cdl_package CYGPKG_KERNEL {
 
     # ---------------------------------------------------------------------
     # SMP support
-    
+
     cdl_component CYGPKG_KERNEL_SMP_SUPPORT {
 	display       "SMP support"
 	flavor        bool
 	requires      CYGPKG_HAL_SMP_SUPPORT
 	default_value 0
     }
-    
+
     # ---------------------------------------------------------------------
     cdl_component CYGPKG_KERNEL_COUNTERS {
         display       "Counters and clocks"
@@ -317,19 +317,32 @@ cdl_package CYGPKG_KERNEL {
                 the set of global flags if present."
         }
 
-        cdl_option CYGPKG_KERNEL_TESTS {
+        cdl_component CYGPKG_KERNEL_TESTS {
             display "Kernel tests"
             flavor  data
             no_define
-            calculated { 
-                "tests/bin_sem0 tests/bin_sem1 tests/bin_sem2 tests/bin_sem3 tests/clock0 tests/clock1 tests/clockcnv tests/clocktruth tests/cnt_sem0 tests/cnt_sem1 tests/except1 tests/flag0 tests/flag1 tests/intr0 tests/kill tests/mbox1 tests/mqueue1 tests/mutex0 tests/mutex1 tests/mutex2 tests/mutex3 tests/release tests/sched1 tests/sync2 tests/sync3 tests/thread0 tests/thread1 tests/thread2" 
-                . ((CYGFUN_KERNEL_API_C) ? " tests/kclock0 tests/kclock1 tests/kexcept1 tests/kflag0 tests/kflag1 tests/kintr0 tests/klock tests/kmbox1 tests/kmutex0 tests/kmutex1 tests/kmutex3 tests/kmutex4 tests/ksched1 tests/ksem0 tests/ksem1 tests/kthread0 tests/kthread1 tests/stress_threads tests/thread_gdb tests/timeslice tests/timeslice2 tests/tm_basic tests/fptest tests/kalarm0" : "")
+            calculated {
+                "tests/bin_sem0 tests/bin_sem1 tests/bin_sem2 tests/bin_sem3 tests/clock0 tests/clock1 tests/clockcnv tests/clocktruth tests/cnt_sem0 tests/cnt_sem1 tests/except1 tests/flag0 tests/flag1 tests/intr0 tests/kill tests/mbox1 tests/mqueue1 tests/mutex0 tests/mutex1 tests/mutex2 tests/mutex3 tests/release tests/sched1 tests/sync2 tests/sync3 tests/thread0 tests/thread1 tests/thread2"
+                . ((CYGFUN_KERNEL_API_C) ? " tests/kclock0 tests/kclock1 tests/kexcept1 tests/kflag0 tests/kflag1 tests/kintr0 tests/klock tests/kmbox1 tests/kmutex0 tests/kmutex1 tests/kmutex3 tests/kmutex4 tests/ksched1 tests/ksem0 tests/ksem1 tests/kthread0 tests/kthread1 tests/stress_threads tests/thread_gdb tests/timeslice tests/timeslice2 tests/tm_basic tests/kalarm0" : "")
                 . ((!CYGPKG_INFRA_DEBUG && !CYGPKG_KERNEL_INSTRUMENT && CYGFUN_KERNEL_API_C) ? " tests/dhrystone" : "")
                 . ((CYGPKG_KERNEL_SMP_SUPPORT && CYGFUN_KERNEL_API_C) ? " tests/smp" : "")
                 . ((!CYGINT_HAL_TESTS_NO_CACHES && CYGFUN_KERNEL_API_C) ? " tests/kcache1 tests/kcache2" : "")
+                . ((CYGFUN_KERNEL_API_C) ? (" tests/fpint_thread_switch" . (CYGTST_KERNEL_SKIP_MULTI_THREAD_FP_TEST ? " tests/fpinttestf1" :
+                   " tests/fptest tests/fpinttestf tests/fpinttestf2")) : "")
             }
             description   "
                 This option specifies the set of tests for the eCos kernel."
+
+            cdl_option CYGTST_KERNEL_SKIP_MULTI_THREAD_FP_TEST {
+                display       "Suppress multi thread floating point test"
+                flavor        bool
+                default_value 0
+                description "Hardware floating point configurations that do not
+                    preserve FPU context are supposed to fail multi thread FPU
+                    integrity tests. Setting this option to 1 shall suppress
+                    building of such tests and shall build single thread fpu
+                    integrity test instead."
+            }
         }
     }
 }
new file mode 100644
--- /dev/null
+++ b/packages/kernel/current/tests/fpint_thread_switch.cxx
@@ -0,0 +1,512 @@
+//==========================================================================
+//
+//        fpint_thread_switch.cxx
+//
+//        Thread switch delay measurement
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2012 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     ilijak
+// Original code: gthomas (tm_basic.cxx from kernel tests)
+// Date:          2012-12-18
+// Description:   Switch delay measurement between threads that do/don't use
+//                floating point operations.
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+#include <pkgconf/hal.h>
+
+#include <cyg/kernel/sched.hxx>
+#include <cyg/kernel/thread.hxx>
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/mutex.hxx>
+#include <cyg/kernel/sema.hxx>
+#include <cyg/kernel/flag.hxx>
+#include <cyg/kernel/sched.inl>
+#include <cyg/kernel/clock.hxx>
+#include <cyg/kernel/clock.inl>
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>
+
+#include <cyg/kernel/test/stackmon.h>
+#include CYGHWR_MEMORY_LAYOUT_H
+
+
+#ifndef HAL_CLOCK_READ_NS
+#define HAL_CLOCK_READ_NS(__pvalue) \
+CYG_MACRO_START                     \
+    HAL_CLOCK_READ(__pvalue)        \
+    *__pvalue *= 1000;              \
+CYG_MACRO_END
+#endif
+
+//==========================================================================
+// Random number generator. Ripped out of the C fptest.c.
+
+static int CYGBLD_ATTRIB_NO_INLINE rand( unsigned int *seed )
+{
+// This is the code supplied in Knuth Vol 2 section 3.6 p.185 bottom
+
+#define RAND_MAX 0x7fffffff
+#define MM 2147483647    // a Mersenne prime
+#define AA 48271         // this does well in the spectral test
+#define QQ 44488         // (long)(MM/AA)
+#define RR 3399          // MM % AA; it is important that RR<QQ
+
+    *seed = AA*(*seed % QQ) - RR*(unsigned int)(*seed/QQ);
+    if (*seed < 0)
+        *seed += MM;
+
+    return (int)( *seed & RAND_MAX );
+}
+
+// Define this to see the statistics with the first sample datum removed.
+// This can expose the effects of caches on the speed of operations.
+#undef STATS_WITHOUT_FIRST_SAMPLE
+#define STATS_WITHOUT_FIRST_SAMPLE 1
+
+#if defined(CYGFUN_KERNEL_API_C) &&             \
+    defined(CYGSEM_KERNEL_SCHED_MLQUEUE) &&     \
+    defined(CYGVAR_KERNEL_COUNTERS_CLOCK) &&    \
+    !defined(CYGDBG_INFRA_DIAG_USE_DEVICE) &&   \
+    (CYGNUM_KERNEL_SCHED_PRIORITIES > 12)
+
+#define NTHREADS 4
+#include "testaux.hxx"
+
+// Structure used to keep track of times
+typedef struct fun_times {
+    cyg_uint32 start;
+    cyg_uint32 end;
+} fun_times;
+
+#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#define NTEST_THREADS    2
+
+#define NSAMPLES         2
+
+#define NTHREAD_SWITCHES 128
+#define NTHREAD_SWITCHES_TS 16
+
+#define NSAMPLES_SIM 2
+#define NTHREAD_SWITCHES_SIM 4
+#define NTHREAD_SWITCHES_TS_SIM 4
+
+static int nsamples;
+static int ntest_threads;
+static int nthread_switches;
+static int nthread_switches_ts;
+
+static char stacks[NTEST_THREADS][STACK_SIZE] CYGBLD_ATTRIB_ALIGN_MAX;
+static cyg_thread test_threads[NTEST_THREADS];
+static cyg_handle_t threads[NTEST_THREADS];
+static cyg_sem_t test_sem[NTEST_THREADS];
+static int overhead;
+static cyg_sem_t synchro;
+
+static fun_times test2_ft[4][NTHREAD_SWITCHES];
+
+
+static long rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION;
+static long ns_per_system_clock;
+
+void run_thread_switch_test(int);
+
+#ifndef min
+#define min(X,Y) ((X) < (Y) ? (X) : (Y))
+#endif
+
+
+
+// Wait until a clock tick [real time clock] has passed.  This should keep it
+// from happening again during a measurement, thus minimizing any fluctuations
+void
+wait_for_tick(void)
+{
+    cyg_tick_count_t tv0, tv1;
+    tv0 = cyg_current_time();
+    while (true) {
+        tv1 = cyg_current_time();
+        if (tv1 != tv0) break;
+    }
+}
+
+// Display a number of ticks as nanoseconds
+void
+show_ticks_in_ns(cyg_uint32 ticks)
+{
+    long long ns;
+    ns = (ns_per_system_clock * (long long)ticks) / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
+    diag_printf("%8d", (int)(ns));
+}
+
+
+void
+show_times_hdr(void)
+{
+    diag_printf("\n");
+    diag_printf("                                 Confidence\n");
+    diag_printf("     Ave     Min     Max Max-Min  Ave  Min  Samp  Function\n");
+    diag_printf("  ======  ======  ======  ====== ==== ===== ===== ========\n");
+}
+
+void
+show_times_detail(fun_times ft[], int nsamples, char *title, bool ignore_first)
+{
+    int i, delta, min, max, con_ave, con_min, ave_dev;
+    int start_sample, total_samples;
+    cyg_int32 total, ave;
+
+    if (ignore_first) {
+        start_sample = 1;
+        total_samples = nsamples-1;
+    } else {
+        start_sample = 0;
+        total_samples = nsamples;
+    }
+    total = 0;
+    min = 0x7FFFFFFF;
+    max = 0;
+    for (i = start_sample;  i < nsamples;  i++) {
+        if (ft[i].end < ft[i].start) {
+            // Clock wrapped around (timer tick)
+            delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD*1000) - ft[i].start;
+        } else {
+            delta = ft[i].end - ft[i].start;
+        }
+        delta -= overhead;
+        if (delta < 0) delta = 0;
+        total += delta;
+        if (delta < min) min = delta;
+        if (delta > max) max = delta;
+    }
+    ave = total / total_samples;
+    total = 0;
+    ave_dev = 0;
+    for (i = start_sample;  i < nsamples;  i++) {
+        if (ft[i].end < ft[i].start) {
+            // Clock wrapped around (timer tick)
+            delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD*1000) - ft[i].start;
+        } else {
+            delta = ft[i].end - ft[i].start;
+        }
+        delta -= overhead;
+        if (delta < 0) delta = 0;
+        delta = delta - ave;
+        if (delta < 0) delta = -delta;
+        ave_dev += delta;
+    }
+    ave_dev /= total_samples;
+    con_ave = 0;
+    con_min = 0;
+    for (i = start_sample;  i < nsamples;  i++) {
+        if (ft[i].end < ft[i].start) {
+            // Clock wrapped around (timer tick)
+            delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD*1000) - ft[i].start;
+        } else {
+            delta = ft[i].end - ft[i].start;
+        }
+        delta -= overhead;
+        if (delta < 0) delta = 0;
+        if ((delta <= (ave+ave_dev)) && (delta >= (ave-ave_dev))) con_ave++;
+        if ((delta <= (min+ave_dev)) && (delta >= (min-ave_dev))) con_min++;
+    }
+    con_ave = (con_ave * 100) / total_samples;
+    con_min = (con_min * 100) / total_samples;
+    show_ticks_in_ns(ave);
+    show_ticks_in_ns(min);
+    show_ticks_in_ns(max);
+    show_ticks_in_ns(max-min);
+    diag_printf("  %3d%% %3d%%", con_ave, con_min);
+    diag_printf("  %4d", total_samples);
+    diag_printf(" %s\n", title);
+}
+
+void
+show_times(fun_times ft[], int nsamples, char *title)
+{
+#ifndef STATS_WITHOUT_FIRST_SAMPLE
+    show_times_detail(ft, nsamples, title, false);
+#else// STATS_WITHOUT_FIRST_SAMPLE
+    show_times_detail(ft, nsamples, title, true);
+#endif
+}
+
+void
+show_test_parameters(void)
+{
+    diag_printf("\nTesting parameters:\n");
+    diag_printf("   Thread switches:            %5d\n", nthread_switches);
+    diag_printf("   Time unit:         nanoseconds [ns]\n");
+}
+
+void
+end_of_test_group(void)
+{
+    diag_printf("\n");
+}
+
+// Compute a name for a thread
+char *
+thread_name(char *basename, int indx) {
+    return "<<NULL>>";  // Not currently used
+}
+
+// test0 - null test, never executed
+void
+test0(cyg_uint32 indx)
+{
+#ifndef CYGPKG_KERNEL_SMP_SUPPORT
+    // In SMP, somw of these threads will execute
+    diag_printf("test0.%d executed?\n", indx);
+#endif
+    cyg_thread_exit();
+}
+
+// test1 - empty test, simply exit.  Last thread signals parent.
+void
+test1(cyg_uint32 indx)
+{
+    if (indx == (cyg_uint32)(ntest_threads-1)) {
+        cyg_semaphore_post(&synchro);  // Signal that last thread is dying
+    }
+    cyg_thread_exit();
+}
+
+char title[128];
+char* thread_title[2];
+
+volatile int ires __attribute__((unused));
+
+// This thread does not use floating point
+void
+thread_int(cyg_uint32 indx_fp)
+{
+    int i;
+    int fp_i, indx;
+    unsigned int seed;
+    int iop1, iop2;
+
+    fp_i = indx_fp & 0x3;
+    indx = (indx_fp & 0x4) >> 2;
+    thread_title[indx] = "int";
+
+    // Just for symmetry with thread_fp.
+    seed = indx_fp;
+    iop1 = rand(&seed);
+    iop2 = rand(&seed);
+    ires = iop1 + iop2;
+    cyg_semaphore_wait(&test_sem[indx]);
+
+    for (i = 0;  i < nthread_switches;  i++) {
+        ires = iop1 + iop2;
+        if (indx == 0) {
+            HAL_CLOCK_READ_NS(&test2_ft[fp_i][i].start);
+        } else {
+            HAL_CLOCK_READ_NS(&test2_ft[fp_i][i].end);
+        }
+        cyg_thread_yield();
+    }
+    if (indx) {
+        cyg_semaphore_post(&synchro);
+    }
+    cyg_thread_exit();
+}
+
+volatile float fres __attribute__((unused));
+
+// This thread does use floating point
+void
+thread_fp(cyg_uint32 indx_fp)
+{
+    int i;
+    int fp_i, indx;
+    unsigned int seed;
+    float fop1, fop2;
+
+    fp_i = indx_fp & 0x3;
+    indx = (indx_fp & 0x4) >> 2;
+    thread_title[indx] = "fpu";
+
+    // In LAZY mode we need some FP usage to enforce
+    // FPU context saving.
+    seed = indx_fp;
+    fop1 = (float)rand(&seed) / (float)0x7fffffff;
+    fop2 = (float)rand(&seed) / (float)0x7fffffff;
+    fres = fop1 + fop2;
+    cyg_semaphore_wait(&test_sem[indx]);
+
+    for (i = 0;  i < nthread_switches;  i++) {
+        fres = fop1 + fop2;
+        if (indx == 0) {
+            HAL_CLOCK_READ_NS(&test2_ft[fp_i][i].start);
+        } else {
+            HAL_CLOCK_READ_NS(&test2_ft[fp_i][i].end);
+        }
+        cyg_thread_yield();
+    }
+    if (indx) {
+        cyg_semaphore_post(&synchro);
+    }
+    cyg_thread_exit();
+}
+
+void
+run_tests(CYG_ADDRESS id)
+{
+    int tst_i;
+
+    ns_per_system_clock = 1000000/rtc_resolution[1];
+
+    diag_printf("Thread switch test\n");
+    show_test_parameters();
+    // Set my priority lower than any I plan to create
+    cyg_thread_set_priority(cyg_thread_self(), 3);
+
+    // Set up the end-of-threads synchronizer
+    cyg_semaphore_init(&synchro, 0);
+    show_times_hdr();
+#if CYGNUM_TESTS_RUN_COUNT < 0
+    while (1)
+#else
+    int i;
+    for (i = 0;  i < CYGNUM_TESTS_RUN_COUNT;  i++)
+#endif
+        for(tst_i = 0; tst_i < 4; tst_i ++){
+            run_thread_switch_test(tst_i);
+        }
+    CYG_TEST_PASS_FINISH("Thread switching OK");
+}
+
+
+void
+run_thread_switch_test(int fp_i)
+{
+    int i;
+    cyg_thread_entry_t* thr_ent[2];
+
+    for (i = 0;  i < 2;  i++) {
+        cyg_semaphore_init(&test_sem[i], 0);
+    }
+    // Set up for thread context switch
+    thr_ent[0] = !(fp_i & 0x2) ? thread_int : thread_fp;
+    thr_ent[1] = !(fp_i & 0x1) ? thread_int : thread_fp;
+
+    for (i = 0;  i < 2;  i++) {
+        cyg_thread_create(10,         // Priority - just a number
+                thr_ent[i],           // entry
+                (i << 2) | fp_i,      // index
+                thread_name("thread", i),     // Name
+                &stacks[i][0],   // Stack
+                STACK_SIZE,      // Size
+                &threads[i],     // Handle
+                &test_threads[i] // Thread data structure
+            );
+    }
+    for (i = 0;  i < 2;  i++) {
+        cyg_thread_resume(threads[i]);
+    }
+    cyg_thread_delay(2);
+    wait_for_tick(); // Wait until the next clock tick to minimize aberations
+    for (i = 0;  i < 2;  i++) {
+        cyg_semaphore_post(&test_sem[i]);
+    }
+    cyg_semaphore_wait(&synchro);
+    __builtin_strcpy(title, "Thread switch: ");
+    __builtin_strcat(title, thread_title[0]);
+    __builtin_strcat(title,"-");
+    __builtin_strcat(title, thread_title[1]);
+    show_times(test2_ft[fp_i], nthread_switches, title);
+    // Clean up
+    for (i = 0;  i < 2;  i++) {
+        cyg_thread_delete(threads[i]);
+    }
+}
+
+void thread_switch_main( void )
+{
+    CYG_TEST_INIT();
+
+    if (cyg_test_is_simulator) {
+        nsamples = NSAMPLES_SIM;
+        nthread_switches = NTHREAD_SWITCHES_SIM;
+        nthread_switches_ts = NTHREAD_SWITCHES_TS_SIM;
+    } else {
+        nsamples = NSAMPLES;
+        nthread_switches = NTHREAD_SWITCHES;
+        nthread_switches_ts = NTHREAD_SWITCHES_TS;
+    }
+
+    new_thread(run_tests, 0);
+
+    Cyg_Scheduler::scheduler.start();
+
+}
+
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+externC void
+cyg_hal_invoke_constructors();
+#endif
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+    cyg_hal_invoke_constructors();
+#endif
+    thread_switch_main();
+}
+
+#else // CYGFUN_KERNEL_API_C
+
+externC void
+cyg_start( void )
+{
+    CYG_TEST_INIT();
+    CYG_TEST_INFO("Timing tests require:\n"
+                "CYGFUN_KERNEL_API_C && \n"
+                "CYGSEM_KERNEL_SCHED_MLQUEUE &&\n"
+                "CYGVAR_KERNEL_COUNTERS_CLOCK &&\n"
+                "!CYGDBG_INFRA_DIAG_USE_DEVICE &&\n"
+                "(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n");
+    CYG_TEST_NA("Timing tests requirements");
+}
+#endif // CYGFUN_KERNEL_API_C, etc.
+
+// EOF fpint_thread_switch.cxx
new file mode 100644
--- /dev/null
+++ b/packages/kernel/current/tests/fpinttestf.c
@@ -0,0 +1,588 @@
+//==========================================================================
+//
+//        fpinttestf.c
+//
+//        Basic FPU integrity test
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2012 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     ilijak
+// Original code: nickg@calivar.com
+// Contributors:
+// Date:          2012-12-18
+// Description:   Simple FPU test with a mix of threads that do and do not use
+//                floating point.
+//                This is a modification of the original FPU test, and presents
+//                both "integer" and "float" threads in order to enforce LAZY
+//                context switching. Single precision floating point is used.
+//                This is not very sophisticated as far
+//                as checking FPU performance or accuracy. It is more
+//                concerned with checking that several threads doing FP
+//                operations do not interfere with eachother's use of the
+//                FPU.
+//                Note: NONE context switching scheme should NOT pass this test with
+//                      multiple FP threads. Look for fpinttestf1.c instead.
+//
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+#include <pkgconf/hal.h>
+
+#include <cyg/hal/hal_arch.h>
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>
+
+#include <cyg/kernel/test/stackmon.h>
+#include CYGHWR_MEMORY_LAYOUT_H
+
+//==========================================================================
+
+#ifndef FP_THREADS_N
+#define FP_THREADS_N 3
+#define FP_TEST_NAME "FP test"
+#endif
+
+#if defined(CYGFUN_KERNEL_API_C) &&                                    \
+    defined(CYGSEM_KERNEL_SCHED_MLQUEUE) &&                            \
+    (CYGNUM_KERNEL_SCHED_PRIORITIES > 12) &&                           \
+    (CYGMEM_REGION_ram_SIZE >= (49152-4096)) &&                        \
+    (!defined(CYGTST_KERNEL_SKIP_MULTI_THREAD_FP_TEST) || (FP_THREADS_N == 1))
+
+//==========================================================================
+// Base priority for all threads.
+
+#define BASE_PRI        5
+
+//==========================================================================
+// Runtime
+//
+// This is the number of ticks that the program will run for. 3000
+// ticks is equal to 30 seconds in the default configuration. For
+// simulators we reduce the run time to 3 simulated seconds.
+
+#define RUN_TICKS       3000
+#define RUN_TICKS_SIM   300
+
+//==========================================================================
+// Thread parameters
+
+#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_MINIMUM
+#define THREADS_N 8
+static cyg_uint8 stacks[THREADS_N][STACK_SIZE] CYGBLD_ATTRIB_ALIGN_MAX;
+static cyg_handle_t thread[THREADS_N];
+static cyg_thread thread_struct[THREADS_N];
+static unsigned long iter_n[THREADS_N];
+
+//==========================================================================
+// Alarm parameters.
+
+static cyg_alarm alarm_struct;
+static cyg_handle_t alarm;
+
+static cyg_count8 cur_thread = 0;
+static cyg_count32 alarm_ticks = 0;
+static cyg_count32 run_ticks = RUN_TICKS;
+
+//==========================================================================
+
+static int errors = 0;
+
+//==========================================================================
+// Random number generator. Ripped out of the C library.
+
+static int CYGBLD_ATTRIB_NO_INLINE rand( unsigned int *seed )
+{
+// This is the code supplied in Knuth Vol 2 section 3.6 p.185 bottom
+
+#define RAND_MAX 0x7fffffff
+#define MM 2147483647    // a Mersenne prime
+#define AA 48271         // this does well in the spectral test
+#define QQ 44488         // (long)(MM/AA)
+#define RR 3399          // MM % AA; it is important that RR<QQ
+
+    *seed = AA*(*seed % QQ) - RR*(unsigned int)(*seed/QQ);
+    if (*seed < 0)
+        *seed += MM;
+
+    return (int)( *seed & RAND_MAX );
+}
+
+
+//==========================================================================
+// Test calculation.
+//
+// Generates an array of random FP values and then repeatedly applies
+// a calculation to them and checks that the same result is reached
+// each time. The calculation, in the macro CALC, is intended to make
+// maximum use of the FPU registers. However, the i386 compiler
+// doesn't let this expression get very complex before it starts
+// spilling values out to memory.
+
+static void do_test( float *values,
+                     int count,
+                     int loops,
+                     int test,
+                     const char *name)
+{
+    unsigned int i, j;
+    // volatiles necessary to force
+    // values to 32 bits for comparison
+    volatile float sum = 1.0;
+    volatile float last_sum;
+    unsigned int seed;
+
+    cyg_uint32 iter = 0;
+    int thread_i = name[__builtin_strlen(name)-1]-'1';
+
+#define V(__i) (values[(__i)%count])
+#define CALC ((V(i-1)*V(i+1))*(V(i-2)*V(i+2))*(V(i-3)*sum))
+
+    seed = ((unsigned int)&i)*count;
+
+    // Set up an array of values...
+    for( i = 0; i < count; i++ )
+        values[i] = (float)rand( &seed )/(float)0x7fffffff;
+
+    // Now calculate something from them...
+    for( i = 0; i < count; i++ )
+        sum += CALC;
+
+    last_sum = sum;
+
+    // Now recalculate the sum in a loop and look for errors
+    for( j = 0; j < loops ; j++ )
+    {
+        iter++;
+        if(thread_i < 3)
+            iter_n[thread_i]++;
+        sum = 1.0;
+        for( i = 0; i < count; i++ )
+            sum += CALC;
+
+        if( sum != last_sum )
+        {
+            union float_int_union {
+                float d;
+                cyg_uint32 i;
+            } diu_sum, diu_lastsum;
+
+            diu_sum.d = sum;
+            diu_lastsum.d = last_sum;
+
+            errors++;
+            if (sizeof(float) != sizeof(cyg_uint32)) {
+                diag_printf("Warning: sizeof(float) != sizeof(cyg_uint32), therefore next line may\n"
+                            "have invalid sum/last_sum values\n");
+            }
+            diag_printf("%s: Sum mismatch! %d sum=[%08x] last_sum=[%08x]\n",
+                        name,j, diu_sum.i, diu_lastsum.i );
+
+        }
+#if 0
+        if( ((j*count)%1000000) == 0 )
+            diag_printf("INFO:<%s: %2d calculations done>\n",name,j*count);
+#endif
+    }
+#if 0
+    if(thread_i < 3)
+        diag_printf("INFO:<%s [%d]: %2d calculations done>\n",name,thread_i,j*count);
+#endif
+    if(thread_i < 3)
+        iter_n[thread_i] = iter;
+}
+
+
+//==========================================================================
+// Test calculation.
+//
+// Generates an array of random integer values and then repeatedly applies
+// a calculation to them and checks that the same result is reached
+// each time.
+
+static void do_int_test( int *values,
+                     int count,
+                     int loops,
+                     int test,
+                     const char *name)
+{
+    unsigned int i, j;
+    // volatiles necessary to force
+    // values to 32 bits for comparison
+    volatile int sum = 1;
+    volatile int last_sum;
+    unsigned int seed;
+#if 0
+    cyg_uint32 ctrlreg;
+#endif
+    cyg_uint32 iter = 0;
+    int thread_i = name[__builtin_strlen(name)-1]-'1';
+
+#define VI(__i) (values[(__i)%count])
+#define CALCI ((VI(i-1)*VI(i+1))*(VI(i-2)*VI(i+2))*(VI(i-3)*sum))
+
+    seed = ((unsigned int)&i)*count;
+
+    // Set up an array of values...
+    for( i = 0; i < count; i++ )
+        values[i] = rand( &seed );
+
+    // Now calculate something from them...
+    for( i = 0; i < count; i++ )
+        sum += CALC;
+
+    last_sum = sum;
+
+    // Now recalculate the sum in a loop and look for errors
+    for( j = 0; j < loops ; j++ )
+    {
+        iter++;
+        if(thread_i < 8)
+            iter_n[thread_i]++;
+        sum = 1;
+        for( i = 0; i < count; i++ )
+            sum += CALC;
+
+        if( sum != last_sum )
+        {
+            errors++;
+            diag_printf("%s: Sum mismatch! %d sum=[%08x] last_sum=[%08x]\n",
+                        name,j, sum, last_sum );
+        }
+#if 0
+        CYGARC_MRS(ctrlreg, control);
+        if(ctrlreg & 0x04){
+            diag_printf("%s: control = 0x%08x\n", name, ctrlreg);
+        }
+#endif
+#if 0
+        if( ((j*count)%1000000) == 0 )
+            diag_printf("INFO:<%s: %2d calculations done>\n",name,j*count);
+#endif
+    }
+}
+
+//==========================================================================
+// Alarm handler
+//
+// This is called every tick. It lowers the priority of the currently
+// running thread and raises the priority of the next. Thus we
+// implement a form of timelslicing between the threads at one tick
+// granularity.
+
+static void alarm_fn(cyg_handle_t alarm, cyg_addrword_t data)
+{
+    alarm_ticks++;
+    unsigned long iter_sum;
+
+    if( alarm_ticks >= run_ticks )
+    {
+        if( errors )
+            CYG_TEST_FAIL("Errors detected");
+        else
+            CYG_TEST_PASS("OK");
+
+        iter_sum = + iter_n[0] + iter_n[1] + iter_n[2] + iter_n[3]+ iter_n[4] + iter_n[5]+ iter_n[6] + iter_n[7];
+        diag_printf("Iterations = %lu+%lu+%lu+%lu+%lu+%lu+%lu+%lu",
+                iter_n[0], iter_n[1], iter_n[2], iter_n[3], iter_n[4], iter_n[5], iter_n[6], iter_n[7]);
+        diag_printf("=%lu\n", iter_sum);
+        CYG_TEST_FINISH("FP Test done");
+    }
+    else
+    {
+        cyg_thread_set_priority( thread[cur_thread], BASE_PRI );
+
+        cur_thread = (cur_thread+1)%8;
+
+        cyg_thread_set_priority( thread[cur_thread], BASE_PRI-1 );
+    }
+}
+
+
+//==========================================================================
+// Floating point threads
+//
+#define FP1_COUNT 1000
+
+static float fpt1_values[FP1_COUNT];
+
+void fptest1( CYG_ADDRWORD id )
+{
+    while(1)
+        do_test( fpt1_values, FP1_COUNT, 2000000000, id, "fptest1" );
+}
+
+//==========================================================================
+#if (CYGMEM_REGION_ram_SIZE / 8 / 2) < 10000
+#define FP2_COUNT (CYGMEM_REGION_ram_SIZE / 8 / 2)
+#else
+#define FP2_COUNT 10000
+#endif
+
+static float fpt2_values[FP2_COUNT];
+
+void fptest2( CYG_ADDRWORD id )
+{
+    while(1)
+        do_test( fpt2_values, FP2_COUNT, 2000000000, id, "fptest2" );
+}
+
+//==========================================================================
+
+#define FP3_COUNT 100
+
+static float fpt3_values[FP3_COUNT];
+
+void fptest3( CYG_ADDRWORD id )
+{
+    while(1)
+        do_test( fpt3_values, FP3_COUNT, 2000000000, id, "fptest3" );
+}
+
+//==========================================================================
+// Integral threads
+//
+
+#define INT1_COUNT 1000
+
+static int int1_values[INT1_COUNT];
+
+void inttest4( CYG_ADDRWORD id )
+{
+    while(1)
+        do_int_test( int1_values, INT1_COUNT, 2000000000, id, "inttest4" );
+}
+
+#define INT2_COUNT 1000
+
+static int int2_values[INT2_COUNT];
+
+void inttest5( CYG_ADDRWORD id )
+{
+    while(1)
+        do_int_test( int2_values, INT2_COUNT, 2000000000, id, "inttest5" );
+}
+
+#define INT3_COUNT 1000
+
+static int int3_values[INT3_COUNT];
+
+void inttest6( CYG_ADDRWORD id )
+{
+    while(1)
+        do_int_test( int3_values, INT3_COUNT, 2000000000, id, "inttest6" );
+}
+
+
+#define INT4_COUNT 1000
+
+static int int4_values[INT4_COUNT];
+
+void inttest7( CYG_ADDRWORD id )
+{
+    while(1)
+        do_int_test( int4_values, INT4_COUNT, 2000000000, id, "inttest7" );
+}
+
+#define INT5_COUNT 1000
+
+static int int5_values[INT5_COUNT];
+
+void inttest8( CYG_ADDRWORD id )
+{
+    while(1)
+        do_int_test( int5_values, INT5_COUNT, 2000000000, id, "inttest8" );
+}
+
+//======================================================================================
+// Main
+
+void fptest_main( void )
+{
+    CYG_TEST_INIT();
+
+    if( cyg_test_is_simulator )
+    {
+        run_ticks = RUN_TICKS_SIM;
+    }
+    CYG_TEST_INFO("Run fptest in cyg_start");
+    do_test( fpt3_values, FP3_COUNT, 1000, 0, "start" );
+    CYG_TEST_INFO( "cyg_start run done");
+
+    cyg_thread_create( BASE_PRI-1,
+                       fptest1,
+                       0,
+                       "fptest1",
+                       &stacks[0][0],
+                       STACK_SIZE,
+                       &thread[0],
+                       &thread_struct[0]);
+#if FP_THREADS_N > 0
+    cyg_thread_resume( thread[0] );
+#endif
+    cyg_thread_create( BASE_PRI,
+                       fptest2,
+                       1,
+                       "fptest2",
+                       &stacks[1][0],
+                       STACK_SIZE,
+                       &thread[1],
+                       &thread_struct[1]);
+
+#if FP_THREADS_N > 1
+    cyg_thread_resume( thread[1] );
+#endif
+    cyg_thread_create( BASE_PRI,
+                       fptest3,
+                       2,
+                       "fptest3",
+                       &stacks[2][0],
+                       STACK_SIZE,
+                       &thread[2],
+                       &thread_struct[2]);
+
+#if FP_THREADS_N > 2
+    cyg_thread_resume( thread[2] );
+#endif
+
+    cyg_thread_create( BASE_PRI,
+                       inttest4,
+                       3,
+                       "inttest4",
+                       &stacks[3][0],
+                       STACK_SIZE,
+                       &thread[3],
+                       &thread_struct[3]);
+
+    cyg_thread_resume( thread[3] );
+
+    cyg_thread_create( BASE_PRI,
+                       inttest5,
+                       4,
+                       "inttest5",
+                       &stacks[4][0],
+                       STACK_SIZE,
+                       &thread[4],
+                       &thread_struct[4]);
+
+    cyg_thread_resume( thread[4] );
+
+    cyg_thread_create( BASE_PRI,
+                       inttest6,
+                       5,
+                       "inttest6",
+                       &stacks[5][0],
+                       STACK_SIZE,
+                       &thread[5],
+                       &thread_struct[5]);
+
+    cyg_thread_resume( thread[5] );
+
+    cyg_thread_create( BASE_PRI,
+                       inttest7,
+                       6,
+                       "inttest7",
+                       &stacks[6][0],
+                       STACK_SIZE,
+                       &thread[6],
+                       &thread_struct[6]);
+
+    cyg_thread_resume( thread[6] );
+
+    cyg_thread_create( BASE_PRI,
+                       inttest8,
+                       7,
+                       "inttest8",
+                       &stacks[7][0],
+                       STACK_SIZE,
+                       &thread[7],
+                       &thread_struct[7]);
+
+    cyg_thread_resume( thread[7] );
+
+    cyg_alarm_create( cyg_real_time_clock(),
+                      alarm_fn,
+                      0,
+                      &alarm,
+                      &alarm_struct );
+
+    cyg_alarm_initialize( alarm, cyg_current_time()+1, 1 );
+
+    cyg_scheduler_start();
+
+}
+
+//==========================================================================
+
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+externC void
+cyg_hal_invoke_constructors();
+#endif
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+    cyg_hal_invoke_constructors();
+#endif
+    fptest_main();
+}
+
+//==========================================================================
+
+#else // CYGFUN_KERNEL_API_C...
+
+externC void
+cyg_start( void )
+{
+    CYG_TEST_INIT();
+    CYG_TEST_INFO(FP_TEST_NAME " requires:\n"
+                "CYGFUN_KERNEL_API_C && \n"
+                "CYGSEM_KERNEL_SCHED_MLQUEUE && \n"
+                "(CYGNUM_KERNEL_SCHED_PRIORITIES > 12) &&\n"
+                "(CYGMEM_REGION_ram_SIZE >= (49152-4096)) &&\n"
+                "(!defined(CYGHWR_HAL_CORTEXM_FPU_SWITCH_NONE) || (FP_THREADS_N == 1))"
+                );
+    CYG_TEST_NA("FP test requirements");
+}
+
+#endif // CYGFUN_KERNEL_API_C, etc.
+
+//==========================================================================
+// EOF fpinttestf.c
new file mode 100644
--- /dev/null
+++ b/packages/kernel/current/tests/fpinttestf1.c
@@ -0,0 +1,58 @@
+//==========================================================================
+//
+//        fpinttestf1.cxx
+//
+//        Basic FPU integrity test for NONE context switching scheme
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2012, 2013 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     ilijak
+// Contributors:
+// Date:          2012-12-18
+// Description:   Simple FPU test with a mix of threads that do and do not use
+//                floating point.
+//                This is a special case of fpinttestf.c with single FP thread.
+//
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#define FP_THREADS_N 1
+#define FP_TEST_NAME "FP test for switching scheme NONE"
+
+#include "fpinttestf.c"
+
+//==========================================================================
+// EOF fpinttestf1.c
new file mode 100644
--- /dev/null
+++ b/packages/kernel/current/tests/fpinttestf2.c
@@ -0,0 +1,400 @@
+//==========================================================================
+//
+//        fpinttestf2.c
+//
+//        Basic FPU integrity test
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2012 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     ilijak
+// Original code: nickg@calivar.com
+// Contributors:
+// Date:          2012-12-18
+// Description:   Simple FPU test with a mix of threads that do and do not use
+//                floating point.
+//                This is a modification of the original FPU test, and presents
+//                both "integer" and "float" threads in order to enforce LAZY
+//                context switching. Single precision floating point is used.
+//                This is not very sophisticated as far
+//                as checking FPU performance or accuracy. It is more
+//                concerned with checking that several threads doing FP
+//                operations do not interfere with eachother's use of the
+//                FPU.
+//
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+#include <pkgconf/hal.h>
+
+#include <cyg/hal/hal_arch.h>
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>
+
+#include <cyg/kernel/test/stackmon.h>
+#include CYGHWR_MEMORY_LAYOUT_H
+
+//==========================================================================
+
+#if defined(CYGFUN_KERNEL_API_C) &&               \
+    defined(CYGSEM_KERNEL_SCHED_MLQUEUE) &&       \
+    (CYGNUM_KERNEL_SCHED_PRIORITIES > 12) &&      \
+    (CYGMEM_REGION_ram_SIZE >= (49152-4096)) &&   \
+    (!defined(CYGHWR_HAL_CORTEXM_FPU_SWITCH_NONE))
+
+
+//==========================================================================
+// Base priority for all threads.
+
+#define BASE_PRI        5
+
+//==========================================================================
+// Runtime
+//
+// This is the number of ticks that the program will run for. 3000
+// ticks is equal to 30 seconds in the default configuration. For
+// simulators we reduce the run time to 3 simulated seconds.
+
+#define RUN_TICKS       3000
+#define RUN_TICKS_SIM   300
+
+//==========================================================================
+// Thread parameters
+
+#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define THREADS_N 2
+static cyg_uint8 stacks[THREADS_N][STACK_SIZE] CYGBLD_ATTRIB_ALIGN_MAX;
+static cyg_handle_t thread[THREADS_N];
+static cyg_thread thread_struct[THREADS_N];
+static unsigned long iter_n[THREADS_N];
+
+//==========================================================================
+// Alarm parameters.
+
+static cyg_alarm alarm_struct;
+static cyg_handle_t alarm;
+
+volatile static cyg_count32 alarm_ticks = 0;
+static cyg_count32 run_ticks = RUN_TICKS;
+
+//==========================================================================
+
+static int errors = 0;
+
+//==========================================================================
+// Random number generator. Ripped out of the C library.
+
+static int CYGBLD_ATTRIB_NO_INLINE rand( unsigned int *seed )
+{
+// This is the code supplied in Knuth Vol 2 section 3.6 p.185 bottom
+
+#define RAND_MAX 0x7fffffff
+#define MM 2147483647    // a Mersenne prime
+#define AA 48271         // this does well in the spectral test
+#define QQ 44488         // (long)(MM/AA)
+#define RR 3399          // MM % AA; it is important that RR<QQ
+
+    *seed = AA*(*seed % QQ) - RR*(unsigned int)(*seed/QQ);
+    if (*seed < 0)
+        *seed += MM;
+
+    return (int)( *seed & RAND_MAX );
+}
+
+
+//==========================================================================
+// Test calculation.
+// Generates an array of random FP values and then thread repeatedly
+// alternates following cases:
+//    - Floatin point calculation occur before it yields;
+//    - No floating point instructions occur before it yields;
+// In addition the re-calculation is called either directly or by means of
+// proxy in order to enforce context stacking in different stack locations
+// Floating point calculation checks whether the same result is reached
+// on every repetition.
+// 
+
+
+#define V(__i) (values[(__i)%count])
+#define CALC ((V(i-1)*V(i+1))*(V(i-2)*V(i+2))*(V(i-3)*sum))
+
+volatile unsigned int fint;
+
+void  CYGBLD_ATTRIB_NO_INLINE
+recalc (float *values, float last_sum, cyg_uint32 iter, int thread_i,
+                    int count, const char *name, unsigned int loop_i)
+{
+    volatile float sum = 1.0;
+    unsigned int i;
+    
+    iter++;
+    if(thread_i < 3)
+        iter_n[thread_i]++;
+    sum = 1.0;
+    for( i = 0; i < count; i++ )
+        sum += CALC;
+    
+    if( sum != last_sum )
+    {
+        union float_int_union {
+            float d;
+            cyg_uint32 i;
+        } diu_sum, diu_lastsum;
+        
+        diu_sum.d = sum;
+        diu_lastsum.d = last_sum;
+        
+        errors++;
+        if (sizeof(float) != sizeof(cyg_uint32)) {
+            diag_printf("Warning: sizeof(float) != sizeof(cyg_uint32), therefore next line may\n"
+                        "have invalid sum/last_sum values\n");
+        }
+        diag_printf("%s: Sum mismatch! %d sum=[%08x] last_sum=[%08x]\n",
+                    name, loop_i, diu_sum.i, diu_lastsum.i );
+        
+    }
+}
+
+void CYGBLD_ATTRIB_NO_INLINE
+recalc_proxy (float *values, float last_sum, cyg_uint32 iter, int thread_i,
+                                        int count, const char *name, unsigned int loop_i)
+{
+    int ticks;
+    
+    ticks = alarm_ticks;
+    while(ticks == alarm_ticks)
+        CYG_EMPTY_STATEMENT;
+    cyg_thread_yield();
+    ticks = alarm_ticks;
+    while(ticks == alarm_ticks);
+        CYG_EMPTY_STATEMENT;
+    cyg_thread_yield();
+    recalc(values, last_sum, iter, thread_i, count, name, loop_i);
+    cyg_thread_yield();
+    ticks = alarm_ticks;
+    while(ticks == alarm_ticks);    
+        CYG_EMPTY_STATEMENT;
+}
+
+
+static void do_test1( float *values,
+                     int count,
+                     int loops,
+                     int test,
+                     const char *name)
+{
+    unsigned int i, j;
+    // volatiles necessary to force
+    // values to 32 bits for comparison
+    volatile float sum = 1.0;
+    volatile float last_sum;
+    unsigned int seed;
+
+    cyg_uint32 iter = 0;
+    int thread_i = name[__builtin_strlen(name)-1]-'1';
+
+    seed = ((unsigned int)&i)*count;
+
+    // Set up an array of values...
+    for( i = 0; i < count; i++ )
+        values[i] = (float)rand( &seed )/(float)0x7fffffff;
+
+    // Now calculate something from them...
+    for( i = 0; i < count; i++ )
+        sum += CALC;
+
+    last_sum = sum;
+
+    // Now recalculate the sum in a loop and look for errors
+    for( j = 0; j < loops ; j++ )
+    {
+        if(j % 2) {
+            recalc_proxy(values, last_sum, iter, thread_i, count, name, j);
+        } else {
+            recalc(values, last_sum, iter, thread_i, count, name, j);
+        }
+    }
+#if 0
+    if(thread_i < 3)
+        diag_printf("INFO:<%s [%d]: %2d calculations done>\n",name,thread_i,j*count);
+#endif
+    if(thread_i < 3)
+        iter_n[thread_i] = iter;
+}
+
+
+//==========================================================================
+// Alarm handler
+//
+// This is called every tick. It lowers the priority of the currently
+// running thread and raises the priority of the next. Thus we
+// implement a form of timelslicing between the threads at one tick
+// granularity.
+
+static void alarm_fn(cyg_handle_t alarm, cyg_addrword_t data)
+{
+    alarm_ticks++;
+    unsigned long iter_sum;
+
+    if( alarm_ticks >= run_ticks )
+    {
+        if( errors )
+            CYG_TEST_FAIL("Errors detected");
+        else
+            CYG_TEST_PASS("OK");
+
+        iter_sum = + iter_n[0] + iter_n[1];
+        diag_printf("Iterations = %lu+%lu",
+                iter_n[0], iter_n[1]);
+        diag_printf("=%lu\n", iter_sum);
+        CYG_TEST_FINISH("FP Test done");
+    }
+}
+
+
+//==========================================================================
+// Floating point threads
+//
+#define FP1_COUNT 10
+
+static float fpt1_values[FP1_COUNT];
+
+void fptest1( CYG_ADDRWORD id )
+{
+    while(1)
+        do_test1( fpt1_values, FP1_COUNT, 2000000000, id, "fptest1" );
+}
+
+//==========================================================================
+#define FP2_COUNT 11
+
+static float fpt2_values[FP2_COUNT];
+
+void fptest2( CYG_ADDRWORD id )
+{
+    while(1)
+        do_test1( fpt2_values, FP2_COUNT, 2000000000, id, "fptest2" );
+}
+
+//======================================================================================
+// Main
+
+
+void fptest_main( void )
+{
+    CYG_TEST_INIT();
+
+    if( cyg_test_is_simulator )
+    {
+        run_ticks = RUN_TICKS_SIM;
+    }
+    CYG_TEST_INFO("Run fptest in cyg_start");
+    CYG_TEST_INFO( "cyg_start run done");
+
+    cyg_thread_create( BASE_PRI,
+                       fptest1,
+                       0,
+                       "thread1",
+                       &stacks[0][0],
+                       STACK_SIZE,
+                       &thread[0],
+                       &thread_struct[0]);
+    cyg_thread_resume( thread[0] );
+
+    cyg_thread_create( BASE_PRI,
+                       fptest2,
+                       1,
+                       "thread2",
+                       &stacks[1][0],
+                       STACK_SIZE,
+                       &thread[1],
+                       &thread_struct[1]);
+
+    cyg_thread_resume( thread[1] );
+
+    cyg_alarm_create( cyg_real_time_clock(),
+                      alarm_fn,
+                      0,
+                      &alarm,
+                      &alarm_struct );
+
+    cyg_alarm_initialize( alarm, cyg_current_time()+1, 1 );
+
+    cyg_scheduler_start();
+
+}
+
+//==========================================================================
+
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+externC void
+cyg_hal_invoke_constructors();
+#endif
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+    cyg_hal_invoke_constructors();
+#endif
+    fptest_main();
+}
+
+//==========================================================================
+
+#else // CYGFUN_KERNEL_API_C...
+
+externC void
+cyg_start( void )
+{
+    CYG_TEST_INIT();
+    CYG_TEST_INFO("FP test 2 requires:\n"
+                "CYGFUN_KERNEL_API_C && \n"
+                "CYGSEM_KERNEL_SCHED_MLQUEUE && \n"
+                "(CYGNUM_KERNEL_SCHED_PRIORITIES > 12) &&\n"
+                "(CYGMEM_REGION_ram_SIZE >= (49152-4096))\n"
+                "(!defined(CYGHWR_HAL_CORTEXM_FPU_SWITCH_NONE))\n"
+                );
+    CYG_TEST_NA("FP test requirements");
+}
+
+#endif // CYGFUN_KERNEL_API_C, etc.
+
+//==========================================================================
+// EOF fpinttestf2.c