1 /*
2  * Copyright (c) 2013-2015 Travis Geiselbrecht
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #if ARM_WITH_VFP || ARCH_ARM64 || X86_WITH_FPU
24 
25 #include <stdio.h>
26 #include <rand.h>
27 #include <err.h>
28 #include <lib/console.h>
29 #include <app/tests.h>
30 #include <kernel/thread.h>
31 #include <kernel/mutex.h>
32 #include <kernel/semaphore.h>
33 #include <kernel/event.h>
34 #include <platform.h>
35 
36 extern void float_vfp_arm_instruction_test(void);
37 extern void float_vfp_thumb_instruction_test(void);
38 extern void float_neon_arm_instruction_test(void);
39 extern void float_neon_thumb_instruction_test(void);
40 
41 #if !ARM_WITH_VFP_SP_ONLY
42 #define FLOAT float
43 #else
44 #define FLOAT float
45 #endif
46 
47 /* optimize this function to cause it to try to use a lot of registers */
48 __OPTIMIZE("O3")
float_thread(void * arg)49 static int float_thread(void *arg)
50 {
51     FLOAT *val = arg;
52     uint i, j;
53 
54     FLOAT a[16];
55 
56     /* do a bunch of work with floating point to test context switching */
57     a[0] = *val;
58     for (i = 1; i < countof(a); i++) {
59         a[i] = a[i-1] * 1.01f;
60     }
61 
62     for (i = 0; i < 1000000; i++) {
63         a[0] += 0.001f;
64         for (j = 1; j < countof(a); j++) {
65             a[j] += a[j-1] * 0.00001f;
66         }
67     }
68 
69     *val = a[countof(a) - 1];
70 
71     return 1;
72 }
73 
74 #if ARCH_ARM && !ARM_ISA_ARMV7M
arm_float_instruction_trap_test(void)75 static void arm_float_instruction_trap_test(void)
76 {
77     printf("testing fpu trap\n");
78 
79 #if !ARM_ONLY_THUMB
80     float_vfp_arm_instruction_test();
81     float_neon_arm_instruction_test();
82 #endif
83     float_vfp_thumb_instruction_test();
84     float_neon_thumb_instruction_test();
85 
86     printf("if we got here, we probably decoded everything properly\n");
87 }
88 #endif
89 
float_tests(void)90 static void float_tests(void)
91 {
92     printf("floating point test:\n");
93 
94     /* test lazy fpu load on separate thread */
95     thread_t *t[8];
96     FLOAT val[countof(t)];
97 
98     printf("creating %u floating point threads\n", countof(t));
99     for (uint i = 0; i < countof(t); i++) {
100         val[i] = i;
101         char name[32];
102         snprintf(name, sizeof(name), "float %u", i);
103         t[i] = thread_create(name, &float_thread, &val[i], LOW_PRIORITY, DEFAULT_STACK_SIZE);
104         thread_resume(t[i]);
105     }
106 
107     int res;
108     for (uint i = 0; i < countof(t); i++) {
109         thread_join(t[i], &res, INFINITE_TIME);
110         printf("float thread %u returns %d, val %f\n", i, res, val[i]);
111     }
112     printf("the above values should be close\n");
113 
114 #if ARCH_ARM && !ARM_ISA_ARMV7M
115     /* test all the instruction traps */
116     arm_float_instruction_trap_test();
117 #endif
118 }
119 
120 STATIC_COMMAND_START
121 STATIC_COMMAND("float_tests", "floating point test", (console_cmd)&float_tests)
122 STATIC_COMMAND_END(float_tests);
123 
124 #endif // ARM_WITH_VFP || ARCH_ARM64
125