]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/kernel/v2_0/tests/fptest.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / kernel / v2_0 / tests / fptest.c
1 //==========================================================================
2 //
3 //        fptest.cxx
4 //
5 //        Basic FPU test
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 2003 Nick Garnett
12 //
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.
16 //
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
20 // for more details.
21 //
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.
25 //
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.
32 //
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.
35 //
36 // -------------------------------------------
37 //####ECOSGPLCOPYRIGHTEND####
38 //==========================================================================
39 //#####DESCRIPTIONBEGIN####
40 //
41 // Author(s):     nickg@calivar.com
42 // Contributors:  nickg@calivar.com
43 // Date:          2003-01-27
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
48 //                FPU.
49 //
50 //####DESCRIPTIONEND####
51 //==========================================================================
52
53 #include <pkgconf/kernel.h>
54 #include <pkgconf/hal.h>
55
56 #include <cyg/hal/hal_arch.h>
57
58 #include <cyg/kernel/kapi.h>
59
60 #include <cyg/infra/testcase.h>
61 #include <cyg/infra/diag.h>
62
63 //#include <cyg/kernel/test/stackmon.h>
64 #include CYGHWR_MEMORY_LAYOUT_H
65
66 //==========================================================================
67
68 #if defined(CYGFUN_KERNEL_API_C) &&             \
69     defined(CYGSEM_KERNEL_SCHED_MLQUEUE) &&     \
70     (CYGNUM_KERNEL_SCHED_PRIORITIES > 12)
71
72 //==========================================================================
73 // Base priority for all threads.
74
75 #define BASE_PRI        5
76
77 //==========================================================================
78 // Runtime
79 //
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.
83
84 #define RUN_TICKS       3000
85 #define RUN_TICKS_SIM   300
86
87 //==========================================================================
88 // Thread parameters
89
90 #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_MINIMUM)
91
92 static cyg_uint8 stacks[3][STACK_SIZE];
93 static cyg_handle_t thread[3];
94 static cyg_thread thread_struct[3];
95
96 //==========================================================================
97 // Alarm parameters.
98
99 static cyg_alarm alarm_struct;
100 static cyg_handle_t alarm;
101
102 static cyg_count8 cur_thread = 0;
103 static cyg_count32 alarm_ticks = 0;
104 static cyg_count32 run_ticks = RUN_TICKS;
105
106 //==========================================================================
107
108 static int errors = 0;
109
110 //==========================================================================
111 // Random number generator. Ripped out of the C library.
112
113 static int rand( unsigned int *seed )
114 {
115 // This is the code supplied in Knuth Vol 2 section 3.6 p.185 bottom
116
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
122
123     *seed = AA*(*seed % QQ) - RR*(unsigned int)(*seed/QQ);
124     if (*seed < 0)
125         *seed += MM;
126
127     return (int)( *seed & RAND_MAX );
128 }
129
130 //==========================================================================
131 // Test calculation.
132 //
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.
139
140 static void do_test( double *values,
141                      int count,
142                      int loops,
143                      int test,
144                      const char *name)
145 {
146     unsigned int i, j;
147     // volatiles necessary to force
148     // values to 64 bits for comparison
149     volatile double sum = 1.0;
150     volatile double last_sum;
151     unsigned int seed;
152     
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))
155
156     seed = ((unsigned int)&i)*count;
157
158     // Set up an array of values...
159     for( i = 0; i < count; i++ )
160         values[i] = (double)rand( &seed )/(double)0x7fffffff;
161
162     // Now calculate something from them...
163     for( i = 0; i < count; i++ )
164         sum += CALC;
165     last_sum = sum;
166     
167     // Now recalculate the sum in a loop and look for errors
168     for( j = 0; j < loops ; j++ )
169     {
170         sum = 1.0;
171         for( i = 0; i < count; i++ )
172             sum += CALC;
173
174         if( sum != last_sum )
175         {
176             union double_int_union {
177                 double d;
178                 cyg_uint32 i[2];
179             } diu_sum, diu_lastsum;
180
181             diu_sum.d = sum;
182             diu_lastsum.d = last_sum;
183             
184             errors++;
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");
188             }
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] );
191         }
192         
193 #if 0
194         if( ((j*count)%1000000) == 0 )
195             diag_printf("INFO:<%s: %2d calculations done>\n",name,j*count);
196 #endif
197     }
198
199 }
200
201 //==========================================================================
202 // Alarm handler
203 //
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
207 // granularity.
208
209 static void alarm_fn(cyg_handle_t alarm, cyg_addrword_t data)
210 {
211     alarm_ticks++;
212
213     if( alarm_ticks >= run_ticks )
214     {
215         if( errors )
216             CYG_TEST_FAIL("Errors detected");
217         else
218             CYG_TEST_PASS("OK");            
219         
220         CYG_TEST_FINISH("FP Test done");
221     }
222     else
223     {
224         cyg_thread_set_priority( thread[cur_thread], BASE_PRI );
225
226         cur_thread = (cur_thread+1)%3;
227
228         cyg_thread_set_priority( thread[cur_thread], BASE_PRI-1 );
229     }
230 }
231
232
233 //==========================================================================
234
235 #define FP1_COUNT 1000
236
237 static double fpt1_values[FP1_COUNT];
238
239 void fptest1( CYG_ADDRWORD id )
240 {
241     while(1)
242         do_test( fpt1_values, FP1_COUNT, 2000000000, id, "fptest1" );
243 }
244
245 //==========================================================================
246 #if (CYGMEM_REGION_ram_SIZE / 8 / 2) < 10000
247 #define FP2_COUNT (CYGMEM_REGION_ram_SIZE / 8 / 2)
248 #else
249 #define FP2_COUNT 10000
250 #endif
251
252 static double fpt2_values[FP2_COUNT];
253
254 void fptest2( CYG_ADDRWORD id )
255 {
256     while(1)
257         do_test( fpt2_values, FP2_COUNT, 2000000000, id, "fptest2" );
258 }
259
260 //==========================================================================
261
262 #define FP3_COUNT 100
263
264 static double fpt3_values[FP3_COUNT];
265
266 void fptest3( CYG_ADDRWORD id )
267 {
268     while(1)
269         do_test( fpt3_values, FP3_COUNT, 2000000000, id, "fptest3" );
270 }
271
272 //==========================================================================
273
274 void fptest_main( void )
275 {
276     
277     CYG_TEST_INIT();
278
279     if( cyg_test_is_simulator )
280     {
281         run_ticks = RUN_TICKS_SIM;
282     }
283
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");
287     
288     cyg_thread_create( BASE_PRI-1,
289                        fptest1,
290                        0,
291                        "fptest1",
292                        &stacks[0][0],
293                        STACK_SIZE,
294                        &thread[0],
295                        &thread_struct[0]);
296
297     cyg_thread_resume( thread[0] );
298
299     cyg_thread_create( BASE_PRI,
300                        fptest2,
301                        1,
302                        "fptest2",
303                        &stacks[1][0],
304                        STACK_SIZE,
305                        &thread[1],
306                        &thread_struct[1]);
307
308     cyg_thread_resume( thread[1] );
309
310     cyg_thread_create( BASE_PRI,
311                        fptest3,
312                        2,
313                        "fptest3",
314                        &stacks[2][0],
315                        STACK_SIZE,
316                        &thread[2],
317                        &thread_struct[2]);
318
319     cyg_thread_resume( thread[2] );
320
321     cyg_alarm_create( cyg_real_time_clock(),
322                       alarm_fn,
323                       0,
324                       &alarm,
325                       &alarm_struct );
326
327     cyg_alarm_initialize( alarm, cyg_current_time()+1, 1 );
328     
329     cyg_scheduler_start();
330
331 }
332
333 //==========================================================================
334
335 #ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
336 externC void
337 cyg_hal_invoke_constructors();
338 #endif
339
340 externC void
341 cyg_start( void )
342 {
343 #ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
344     cyg_hal_invoke_constructors();
345 #endif
346     fptest_main();
347 }   
348
349 //==========================================================================
350
351 #else // CYGFUN_KERNEL_API_C...
352
353 externC void
354 cyg_start( void )
355 {
356     CYG_TEST_INIT();
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");
362 }
363
364 #endif // CYGFUN_KERNEL_API_C, etc.
365
366 //==========================================================================
367 // EOF fptest.cxx