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