1 //==========================================================================
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 2003 Nick Garnett
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // -------------------------------------------
37 //####ECOSGPLCOPYRIGHTEND####
38 //==========================================================================
39 //#####DESCRIPTIONBEGIN####
41 // Author(s): nickg@calivar.com
42 // Contributors: nickg@calivar.com
44 // Description: Simple FPU test. This is not very sophisticated as far
45 // as checking FPU performance or accuracy. It is more
46 // concerned with checking that several threads doing FP
47 // operations do not interfere with eachother's use of the
50 //####DESCRIPTIONEND####
51 //==========================================================================
53 #include <pkgconf/kernel.h>
54 #include <pkgconf/hal.h>
56 #include <cyg/hal/hal_arch.h>
58 #include <cyg/kernel/kapi.h>
60 #include <cyg/infra/testcase.h>
61 #include <cyg/infra/diag.h>
63 //#include <cyg/kernel/test/stackmon.h>
64 #include CYGHWR_MEMORY_LAYOUT_H
66 //==========================================================================
68 #if defined(CYGFUN_KERNEL_API_C) && \
69 defined(CYGSEM_KERNEL_SCHED_MLQUEUE) && \
70 (CYGNUM_KERNEL_SCHED_PRIORITIES > 12)
72 //==========================================================================
73 // Base priority for all threads.
77 //==========================================================================
80 // This is the number of ticks that the program will run for. 3000
81 // ticks is equal to 30 seconds in the default configuration. For
82 // simulators we reduce the run time to 3 simulated seconds.
84 #define RUN_TICKS 3000
85 #define RUN_TICKS_SIM 300
87 //==========================================================================
90 #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_MINIMUM)
92 static cyg_uint8 stacks[3][STACK_SIZE];
93 static cyg_handle_t thread[3];
94 static cyg_thread thread_struct[3];
96 //==========================================================================
99 static cyg_alarm alarm_struct;
100 static cyg_handle_t alarm;
102 static cyg_count8 cur_thread = 0;
103 static cyg_count32 alarm_ticks = 0;
104 static cyg_count32 run_ticks = RUN_TICKS;
106 //==========================================================================
108 static int errors = 0;
110 //==========================================================================
111 // Random number generator. Ripped out of the C library.
113 static int rand( unsigned int *seed )
115 // This is the code supplied in Knuth Vol 2 section 3.6 p.185 bottom
117 #define RAND_MAX 0x7fffffff
118 #define MM 2147483647 // a Mersenne prime
119 #define AA 48271 // this does well in the spectral test
120 #define QQ 44488 // (long)(MM/AA)
121 #define RR 3399 // MM % AA; it is important that RR<QQ
123 *seed = AA*(*seed % QQ) - RR*(unsigned int)(*seed/QQ);
127 return (int)( *seed & RAND_MAX );
130 //==========================================================================
133 // Generates an array of random FP values and then repeatedly applies
134 // a calculation to them and checks that the same result is reached
135 // each time. The calculation, in the macro CALC, is intended to make
136 // maximum use of the FPU registers. However, the i386 compiler
137 // doesn't let this expression get very complex before it starts
138 // spilling values out to memory.
140 static void do_test( double *values,
147 // volatiles necessary to force
148 // values to 64 bits for comparison
149 volatile double sum = 1.0;
150 volatile double last_sum;
153 #define V(__i) (values[(__i)%count])
154 #define CALC ((V(i-1)*V(i+1))*(V(i-2)*V(i+2))*(V(i-3)*sum))
156 seed = ((unsigned int)&i)*count;
158 // Set up an array of values...
159 for( i = 0; i < count; i++ )
160 values[i] = (double)rand( &seed )/(double)0x7fffffff;
162 // Now calculate something from them...
163 for( i = 0; i < count; i++ )
167 // Now recalculate the sum in a loop and look for errors
168 for( j = 0; j < loops ; j++ )
171 for( i = 0; i < count; i++ )
174 if( sum != last_sum )
176 union double_int_union {
179 } diu_sum, diu_lastsum;
182 diu_lastsum.d = last_sum;
185 if (sizeof(double) != 2*sizeof(cyg_uint32)) {
186 diag_printf("Warning: sizeof(double) != 2*sizeof(cyg_uint32), therefore next line may\n"
187 "have invalid sum/last_sum values\n");
189 diag_printf("%s: Sum mismatch! %d sum=[%08x:%08x] last_sum=[%08x:%08x]\n",
190 name,j, diu_sum.i[0], diu_sum.i[1], diu_lastsum.i[0], diu_lastsum.i[1] );
194 if( ((j*count)%1000000) == 0 )
195 diag_printf("INFO:<%s: %2d calculations done>\n",name,j*count);
201 //==========================================================================
204 // This is called every tick. It lowers the priority of the currently
205 // running thread and raises the priority of the next. Thus we
206 // implement a form of timelslicing between the threads at one tick
209 static void alarm_fn(cyg_handle_t alarm, cyg_addrword_t data)
213 if( alarm_ticks >= run_ticks )
216 CYG_TEST_FAIL("Errors detected");
220 CYG_TEST_FINISH("FP Test done");
224 cyg_thread_set_priority( thread[cur_thread], BASE_PRI );
226 cur_thread = (cur_thread+1)%3;
228 cyg_thread_set_priority( thread[cur_thread], BASE_PRI-1 );
233 //==========================================================================
235 #define FP1_COUNT 1000
237 static double fpt1_values[FP1_COUNT];
239 void fptest1( CYG_ADDRWORD id )
242 do_test( fpt1_values, FP1_COUNT, 2000000000, id, "fptest1" );
245 //==========================================================================
246 #if (CYGMEM_REGION_ram_SIZE / 8 / 2) < 10000
247 #define FP2_COUNT (CYGMEM_REGION_ram_SIZE / 8 / 2)
249 #define FP2_COUNT 10000
252 static double fpt2_values[FP2_COUNT];
254 void fptest2( CYG_ADDRWORD id )
257 do_test( fpt2_values, FP2_COUNT, 2000000000, id, "fptest2" );
260 //==========================================================================
262 #define FP3_COUNT 100
264 static double fpt3_values[FP3_COUNT];
266 void fptest3( CYG_ADDRWORD id )
269 do_test( fpt3_values, FP3_COUNT, 2000000000, id, "fptest3" );
272 //==========================================================================
274 void fptest_main( void )
279 if( cyg_test_is_simulator )
281 run_ticks = RUN_TICKS_SIM;
284 CYG_TEST_INFO("Run fptest in cyg_start");
285 do_test( fpt3_values, FP3_COUNT, 1000, 0, "start" );
286 CYG_TEST_INFO( "cyg_start run done");
288 cyg_thread_create( BASE_PRI-1,
297 cyg_thread_resume( thread[0] );
299 cyg_thread_create( BASE_PRI,
308 cyg_thread_resume( thread[1] );
310 cyg_thread_create( BASE_PRI,
319 cyg_thread_resume( thread[2] );
321 cyg_alarm_create( cyg_real_time_clock(),
327 cyg_alarm_initialize( alarm, cyg_current_time()+1, 1 );
329 cyg_scheduler_start();
333 //==========================================================================
335 #ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
337 cyg_hal_invoke_constructors();
343 #ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
344 cyg_hal_invoke_constructors();
349 //==========================================================================
351 #else // CYGFUN_KERNEL_API_C...
357 CYG_TEST_INFO("FP test requires:\n"
358 "CYGFUN_KERNEL_API_C && \n"
359 "CYGSEM_KERNEL_SCHED_MLQUEUE && \n"
360 "(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n");
361 CYG_TEST_NA("FP test requirements");
364 #endif // CYGFUN_KERNEL_API_C, etc.
366 //==========================================================================