Mercurial > ecos
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