|
552
|
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 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
|
|
37 // at http://sources.redhat.com/ecos/ecos-license/ |
|
|
38 // ------------------------------------------- |
|
|
39 //####ECOSGPLCOPYRIGHTEND#### |
|
|
40 //========================================================================== |
|
|
41 //#####DESCRIPTIONBEGIN#### |
|
|
42 // |
|
|
43 // Author(s): nickg@calivar.com |
|
|
44 // Contributors: nickg@calivar.com |
|
|
45 // Date: 2003-01-27 |
|
|
46 // Description: Simple FPU test. This is not very sophisticated as far |
|
|
47 // as checking FPU performance or accuracy. It is more |
|
|
48 // concerned with checking that several threads doing FP |
|
|
49 // operations do not interfere with eachother's use of the |
|
|
50 // FPU. |
|
|
51 // |
|
|
52 //####DESCRIPTIONEND#### |
|
|
53 //========================================================================== |
|
|
54 |
|
|
55 #include <pkgconf/kernel.h> |
|
|
56 #include <pkgconf/hal.h> |
|
|
57 |
|
|
58 #include <cyg/hal/hal_arch.h> |
|
|
59 |
|
|
60 #include <cyg/kernel/kapi.h> |
|
|
61 |
|
|
62 #include <cyg/infra/testcase.h> |
|
|
63 #include <cyg/infra/diag.h> |
|
|
64 |
|
|
65 //#include <cyg/kernel/test/stackmon.h> |
|
|
66 //#include CYGHWR_MEMORY_LAYOUT_H |
|
|
67 |
|
|
68 //========================================================================== |
|
|
69 |
|
|
70 #if defined(CYGFUN_KERNEL_API_C) && \ |
|
|
71 defined(CYGSEM_KERNEL_SCHED_MLQUEUE) && \ |
|
|
72 (CYGNUM_KERNEL_SCHED_PRIORITIES > 12) |
|
|
73 |
|
|
74 //========================================================================== |
|
|
75 // Multiplier for loop counter. This allows us to tune the runtime of |
|
|
76 // the whole program easily. The current value gives a runtime of |
|
|
77 // about 90s on an 800Mz Pentium III. |
|
|
78 |
|
|
79 #define MULTIPLIER 100 |
|
|
80 |
|
|
81 //========================================================================== |
|
|
82 // Thread parameters |
|
|
83 |
|
|
84 #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_MINIMUM+4096) |
|
|
85 |
|
|
86 cyg_uint8 stacks[3][STACK_SIZE]; |
|
|
87 cyg_handle_t thread[3]; |
|
|
88 cyg_thread thread_struct[3]; |
|
|
89 |
|
|
90 //========================================================================== |
|
|
91 // Random number generator. Ripped out of the C library. |
|
|
92 |
|
|
93 static int rand( unsigned int *seed ) |
|
|
94 { |
|
|
95 // This is the code supplied in Knuth Vol 2 section 3.6 p.185 bottom |
|
|
96 |
|
|
97 #define RAND_MAX 0x7fffffff |
|
|
98 #define MM 2147483647 // a Mersenne prime |
|
|
99 #define AA 48271 // this does well in the spectral test |
|
|
100 #define QQ 44488 // (long)(MM/AA) |
|
|
101 #define RR 3399 // MM % AA; it is important that RR<QQ |
|
|
102 |
|
|
103 *seed = AA*(*seed % QQ) - RR*(unsigned int)(*seed/QQ); |
|
|
104 if (*seed < 0) |
|
|
105 *seed += MM; |
|
|
106 |
|
|
107 return (int)( *seed & RAND_MAX ); |
|
|
108 } |
|
|
109 |
|
|
110 //========================================================================== |
|
|
111 // Test calculation. |
|
|
112 // |
|
|
113 // Generates an array of random FP values and then repeatedly applies |
|
|
114 // a calculation to them and checks that the same result is reached |
|
|
115 // each time. The calculation, in the macro CALC, is intended to make |
|
|
116 // maximum use of the FPU registers. However, the i386 compiler |
|
|
117 // doesn't let this expression get very complex before it starts |
|
|
118 // spilling values out to memory. |
|
|
119 |
|
|
120 static void do_test( double *values, |
|
|
121 int count, |
|
|
122 int loops, |
|
|
123 char *name) |
|
|
124 { |
|
|
125 int i, j; |
|
|
126 double sum = 1.0; |
|
|
127 double last_sum; |
|
|
128 unsigned int seed; |
|
|
129 |
|
|
130 #define V(__i) (values[(__i)%count]) |
|
|
131 #define CALC ((V(i-1)*V(i+1))*(V(i-2)*V(i+2))*(V(i-3)*sum)) |
|
|
132 |
|
|
133 seed = ((unsigned int)&i)*loops*count; |
|
|
134 |
|
|
135 // Set up an array of values... |
|
|
136 for( i = 0; i < count; i++ ) |
|
|
137 values[i] = (double)rand( &seed )/(double)0x7fffffff; |
|
|
138 |
|
|
139 // Now calculate something from them... |
|
|
140 for( i = 0; i < count; i++ ) |
|
|
141 sum += CALC; |
|
|
142 last_sum = sum; |
|
|
143 |
|
|
144 // Now recalculate the sum in a loop and look for errors |
|
|
145 for( j = 0; j < loops; j++ ) |
|
|
146 { |
|
|
147 sum = 1.0; |
|
|
148 for( i = 0; i < count; i++ ) |
|
|
149 sum += CALC; |
|
|
150 |
|
|
151 if( sum != last_sum ) |
|
|
152 diag_printf("%s: Sum mismatch! %d\n",name,j); |
|
|
153 |
|
|
154 last_sum = sum; |
|
|
155 } |
|
|
156 |
|
|
157 } |
|
|
158 |
|
|
159 //========================================================================== |
|
|
160 |
|
|
161 volatile int done[4]; |
|
|
162 |
|
|
163 volatile cyg_tick_count_t start, end; |
|
|
164 |
|
|
165 //========================================================================== |
|
|
166 |
|
|
167 #define FP1_COUNT 1000 |
|
|
168 #define FP1_LOOPS 1000*MULTIPLIER |
|
|
169 |
|
|
170 static double fpt1_values[FP1_COUNT]; |
|
|
171 |
|
|
172 void fptest1( CYG_ADDRWORD id ) |
|
|
173 { |
|
|
174 diag_printf("fptest1: start\n"); |
|
|
175 |
|
|
176 do_test( &fpt1_values, FP1_COUNT, FP1_LOOPS, "fptest1" ); |
|
|
177 |
|
|
178 done[id] = 1; |
|
|
179 |
|
|
180 diag_printf("fptest1: done\n"); |
|
|
181 } |
|
|
182 |
|
|
183 //========================================================================== |
|
|
184 |
|
|
185 #define FP2_COUNT 10000 |
|
|
186 #define FP2_LOOPS 100*MULTIPLIER |
|
|
187 |
|
|
188 static double fpt2_values[FP2_COUNT]; |
|
|
189 |
|
|
190 void fptest2( CYG_ADDRWORD id ) |
|
|
191 { |
|
|
192 diag_printf("fptest2: start\n"); |
|
|
193 |
|
|
194 do_test( &fpt2_values, FP2_COUNT, FP2_LOOPS, "fptest2" ); |
|
|
195 |
|
|
196 done[id] = 1; |
|
|
197 |
|
|
198 diag_printf("fptest2: done\n"); |
|
|
199 } |
|
|
200 |
|
|
201 //========================================================================== |
|
|
202 |
|
|
203 #define FP3_COUNT 10000 |
|
|
204 #define FP3_LOOPS 100*MULTIPLIER |
|
|
205 |
|
|
206 static double fpt3_values[FP3_COUNT]; |
|
|
207 |
|
|
208 void fptest3( CYG_ADDRWORD id ) |
|
|
209 { |
|
|
210 int all_done; |
|
|
211 |
|
|
212 diag_printf("fptest3: start\n"); |
|
|
213 |
|
|
214 do_test( &fpt3_values, FP3_COUNT, FP3_LOOPS, "fptest3" ); |
|
|
215 |
|
|
216 done[id] = 1; |
|
|
217 |
|
|
218 diag_printf("fptest3: done\n"); |
|
|
219 |
|
|
220 // Spin here waiting for the other threads to finish. We should |
|
|
221 // only wake up and test every third or second timeslice. |
|
|
222 do { |
|
|
223 int i; |
|
|
224 |
|
|
225 cyg_thread_yield(); |
|
|
226 |
|
|
227 all_done = 0; |
|
|
228 for( i = 0; i < 4; i++ ) |
|
|
229 all_done += done[i]; |
|
|
230 |
|
|
231 } while(all_done != 4 ); |
|
|
232 |
|
|
233 end = cyg_current_time(); |
|
|
234 |
|
|
235 diag_printf("Elapsed time %d ticks\n",end-start); |
|
|
236 |
|
|
237 CYG_TEST_PASS_FINISH("FP Test OK"); |
|
|
238 |
|
|
239 } |
|
|
240 |
|
|
241 //========================================================================== |
|
|
242 |
|
|
243 void fptest_main( void ) |
|
|
244 { |
|
|
245 |
|
|
246 CYG_TEST_INIT(); |
|
|
247 |
|
|
248 start = cyg_current_time(); |
|
|
249 |
|
|
250 diag_printf("Run fptest1 in cyg_start\n"); |
|
|
251 fptest1( 0 ); |
|
|
252 |
|
|
253 cyg_thread_create( 5, |
|
|
254 fptest1, |
|
|
255 1, |
|
|
256 "fptest1", |
|
|
257 &stacks[0][0], |
|
|
258 STACK_SIZE, |
|
|
259 &thread[0], |
|
|
260 &thread_struct[0]); |
|
|
261 |
|
|
262 cyg_thread_resume( thread[0] ); |
|
|
263 |
|
|
264 cyg_thread_create( 5, |
|
|
265 fptest2, |
|
|
266 2, |
|
|
267 "fptest2", |
|
|
268 &stacks[1][0], |
|
|
269 STACK_SIZE, |
|
|
270 &thread[1], |
|
|
271 &thread_struct[1]); |
|
|
272 |
|
|
273 cyg_thread_resume( thread[1] ); |
|
|
274 |
|
|
275 cyg_thread_create( 5, |
|
|
276 fptest3, |
|
|
277 3, |
|
|
278 "fptest3", |
|
|
279 &stacks[2][0], |
|
|
280 STACK_SIZE, |
|
|
281 &thread[2], |
|
|
282 &thread_struct[2]); |
|
|
283 |
|
|
284 cyg_thread_resume( thread[2] ); |
|
|
285 |
|
|
286 cyg_scheduler_start(); |
|
|
287 |
|
|
288 } |
|
|
289 |
|
|
290 //========================================================================== |
|
|
291 |
|
|
292 #ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
|
|
293 externC void |
|
|
294 cyg_hal_invoke_constructors(); |
|
|
295 #endif |
|
|
296 |
|
|
297 externC void |
|
|
298 cyg_start( void ) |
|
|
299 { |
|
|
300 #ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG |
|
|
301 cyg_hal_invoke_constructors(); |
|
|
302 #endif |
|
|
303 fptest_main(); |
|
|
304 } |
|
|
305 |
|
|
306 //========================================================================== |
|
|
307 |
|
|
308 #else // CYGFUN_KERNEL_API_C... |
|
|
309 |
|
|
310 externC void |
|
|
311 cyg_start( void ) |
|
|
312 { |
|
|
313 CYG_TEST_INIT(); |
|
|
314 CYG_TEST_NA("FP test requires:\n" |
|
|
315 "CYGFUN_KERNEL_API_C && \n" |
|
|
316 "CYGSEM_KERNEL_SCHED_MLQUEUE && \n" |
|
|
317 "(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n"); |
|
|
318 } |
|
|
319 |
|
|
320 #endif // CYGFUN_KERNEL_API_C, etc. |
|
|
321 |
|
|
322 //========================================================================== |
|
|
323 // EOF fptest.cxx |