• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #if defined(__mips_hard_float)
2 
3 #include <elf.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <sys/prctl.h>
7 
8 #if !defined(PR_SET_FP_MODE)
9 #   define PR_SET_FP_MODE 45
10 #endif
11 
12 #if !defined(PR_GET_FP_MODE)
13 #   define PR_GET_FP_MODE 46
14 #endif
15 
16 #define TEST_LD(instruction, source)                              \
17 {                                                                 \
18    unsigned int result1, result2;                                 \
19    __asm__ volatile(                                              \
20       ".set push\n\t"                                             \
21       ".set noreorder\n\t"                                        \
22       "li $t0, 0x5a5a\n\t"                                        \
23       "mtc1 $t0, $f0\n\t"                                         \
24       "mtc1 $t0, $f1\n\t"                                         \
25       "move $t0, %2\n\t"                                          \
26       instruction"\n\t"                                           \
27       "swc1 $f0, %0\n\t"                                          \
28       "swc1 $f1, %1\n\t"                                          \
29       ".set pop\n\t"                                              \
30       : "=m"(result1), "=m"(result2)                              \
31       : "r" (&source)                                             \
32       : "t0", "$f0", "$f1");                                      \
33    printf(instruction" :: lo32(f1): %x, lo32(f0): %x\n",          \
34           result2, result1);                                      \
35 }
36 
37 #define _TEST_ST(instruction)                                     \
38    __asm__ volatile(                                              \
39       ".set push\n\t"                                             \
40       ".set noreorder\n\t"                                        \
41       "li $t0, 0x5a5a\n\t"                                        \
42       "dmtc1 $t0, $f1\n\t"                                        \
43       "move $t0, %0\n\t"                                          \
44       "ldc1 $f0, 0($t0)\n\t"                                      \
45       "move $t0, %1\n\t"                                          \
46       instruction"\n\t"                                           \
47       ".set pop\n\t"                                              \
48       :                                                           \
49       : "r" (&source64), "r" (&result)                            \
50       : "t0", "$f0", "$f1", "memory")
51 
52 #define TEST_ST64(instruction)                                    \
53 {                                                                 \
54    unsigned long result;                                          \
55    _TEST_ST(instruction);                                         \
56    printf(instruction" :: mem: %lx\n", result);                   \
57 }
58 
59 #define TEST_ST32(instruction)                                    \
60 {                                                                 \
61    unsigned int result;                                           \
62    _TEST_ST(instruction);                                         \
63    printf(instruction" :: mem: %x\n", result);                    \
64 }
65 
66 #define TEST_MT(instruction)                                      \
67 {                                                                 \
68    unsigned int result1, result2;                                 \
69    __asm__ volatile(                                              \
70       ".set push\n\t"                                             \
71       ".set noreorder\n\t"                                        \
72       "li $t0, 0x5a5a\n\t"                                        \
73       "mtc1 $t0, $f0\n\t"                                         \
74       "mtc1 $t0, $f1\n\t"                                         \
75       "ld $t0, %2\n\t"                                            \
76       instruction"\n\t"                                           \
77       "swc1 $f0, %0\n\t"                                          \
78       "swc1 $f1, %1\n\t"                                          \
79       ".set pop\n\t"                                              \
80       : "=m"(result1), "=m"(result2)                              \
81       : "m" (source64)                                            \
82       : "t0", "$f0", "$f1");                                      \
83    printf(instruction" :: lo32(f1): %x, lo32(f0): %x\n",          \
84           result2, result1);                                      \
85 }
86 
87 #define TEST_MF(instruction)                                      \
88 {                                                                 \
89    unsigned long result;                                          \
90    __asm__ volatile(                                              \
91       ".set push\n\t"                                             \
92       ".set noreorder\n\t"                                        \
93       "li $t0, 0x5a5a\n\t"                                        \
94       "dmtc1 $t0, $f1\n\t"                                        \
95       "ldc1 $f0, %1\n\t"                                          \
96       "move $t0, $0\n\t"                                          \
97       instruction"\n\t"                                           \
98       "sd $t0, %0\n\t"                                            \
99       ".set pop\n\t"                                              \
100       : "=m" (result)                                             \
101       : "m" (source64)                                            \
102       : "t0", "$f0", "$f1");                                      \
103    printf(instruction" :: t0: %lx\n", result);                    \
104 }
105 
106 #define TEST_MOVE(instruction)                                    \
107 {                                                                 \
108    unsigned int result1, result2;                                 \
109    __asm__ volatile(                                              \
110       ".set push\n\t"                                             \
111       ".set noreorder\n\t"                                        \
112       "li $t0, 0x5a5a\n\t"                                        \
113       "mtc1 $t0, $f0\n\t"                                         \
114       "li $t0, 0x6b6b\n\t"                                        \
115       "mtc1 $t0, $f1\n\t"                                         \
116       "li $t0, 0x7c7c\n\t"                                        \
117       "dmtc1 $t0, $f2\n\t"                                        \
118       "ldc1 $f2, %2\n\t"                                          \
119       instruction"\n\t"                                           \
120       "swc1 $f0, %0\n\t"                                          \
121       "swc1 $f1, %1\n\t"                                          \
122       ".set pop\n\t"                                              \
123       : "=m"(result1), "=m"(result2)                              \
124       : "m" (source64)                                            \
125       : "t0", "$f0", "$f1", "$f2");                               \
126    printf(instruction" :: lo32(f1): %x, lo32(f0): %x\n",          \
127           result2, result1);                                      \
128 }
129 
130 unsigned long source64 = 0x1234567890abcdefull;
131 unsigned int  source32 = 0x12345678u;
132 
133 /* Determine FP mode based on sdc1 behavior
134    returns 1 if FR = 1 mode is detected (assumes FRE = 0) */
get_fp_mode(void)135 static int get_fp_mode(void) {
136    unsigned long result = 0;
137    __asm__ volatile(
138       ".set push\n\t"
139       ".set noreorder\n\t"
140       "lui $t0, 0x3ff0\n\t"
141       "ldc1 $f0, %0\n\t"
142       "mtc1 $t0, $f1\n\t"
143       "sdc1 $f0, %0\n\t"
144       ".set pop\n\t"
145       : "+m"(result)
146       :
147       : "t0", "$f0", "$f1", "memory");
148 
149    return (result != 0x3ff0000000000000ull);
150 }
151 
fatal_error(const char * msg)152 static void fatal_error(const char* msg) {
153    fprintf(stderr, "Error: %s\n", msg);
154    exit(1);
155 }
156 
test(int * fr_prctl,int * fr_detected)157 static void test(int* fr_prctl, int* fr_detected) {
158 
159    *fr_prctl = prctl(PR_GET_FP_MODE);
160    *fr_detected = get_fp_mode();
161 
162    if (*fr_prctl < 0) {
163       fatal_error("prctl(PR_GET_FP_MODE) fails.");
164    }
165 
166    printf("fr_prctl: %d, fr_detected: %d\n", *fr_prctl, *fr_detected);
167 
168    if (*fr_prctl != *fr_detected) {
169       fatal_error("fr_prctl != fr_detected");
170    }
171 
172    TEST_LD("lwc1 $f0, 0($t0)", source32);
173    TEST_LD("lwc1 $f1, 0($t0)", source32);
174 
175    TEST_LD("lwxc1 $f0, $0($t0)", source32);
176    TEST_LD("lwxc1 $f1, $0($t0)", source32);
177 
178    TEST_LD("ldc1 $f0, 0($t0)", source64);
179    TEST_LD("ldc1 $f1, 0($t0)", source64);
180 
181    TEST_LD("ldxc1 $f0, $0($t0)", source64);
182    TEST_LD("ldxc1 $f1, $0($t0)", source64);
183 
184    TEST_ST32("swc1 $f0, 0($t0)");
185    TEST_ST32("swc1 $f1, 0($t0)");
186 
187    TEST_ST32("swxc1 $f0, $0($t0)");
188    TEST_ST32("swxc1 $f1, $0($t0)");
189 
190    TEST_ST64("sdc1 $f0, 0($t0)");
191    TEST_ST64("sdc1 $f1, 0($t0)");
192 
193    TEST_ST64("sdxc1 $f0, $0($t0)");
194    TEST_ST64("sdxc1 $f1, $0($t0)");
195 
196    TEST_MT("mtc1 $t0, $f0");
197    TEST_MT("mtc1 $t0, $f1");
198 
199    TEST_MT("dmtc1 $t0, $f0");
200    TEST_MT("dmtc1 $t0, $f1");
201 
202    TEST_MF("mfc1 $t0, $f0");
203    TEST_MF("mfc1 $t0, $f1");
204 
205    TEST_MF("dmfc1 $t0, $f0");
206    TEST_MF("dmfc1 $t0, $f1");
207 
208    TEST_MOVE("movn.s $f0, $f2, $t0");
209    TEST_MOVE("movn.s $f0, $f1, $t0");
210    TEST_MOVE("movn.s $f1, $f2, $t0");
211    TEST_MOVE("movn.s $f0, $f2, $0");
212    TEST_MOVE("movn.s $f0, $f1, $0");
213    TEST_MOVE("movn.s $f1, $f2, $0");
214 
215    TEST_MOVE("movn.d $f0, $f2, $t0");
216    TEST_MOVE("movn.d $f0, $f1, $t0");
217    TEST_MOVE("movn.d $f1, $f2, $t0");
218    TEST_MOVE("movn.d $f0, $f2, $0");
219    TEST_MOVE("movn.d $f0, $f1, $0");
220    TEST_MOVE("movn.d $f1, $f2, $0");
221 
222    TEST_MOVE("movz.s $f0, $f2, $t0");
223    TEST_MOVE("movz.s $f0, $f1, $t0");
224    TEST_MOVE("movz.s $f1, $f2, $t0");
225    TEST_MOVE("movz.s $f0, $f2, $0");
226    TEST_MOVE("movz.s $f0, $f1, $0");
227    TEST_MOVE("movz.s $f1, $f2, $0");
228 
229    TEST_MOVE("movz.d $f0, $f2, $t0");
230    TEST_MOVE("movz.d $f0, $f1, $t0");
231    TEST_MOVE("movz.d $f1, $f2, $t0");
232    TEST_MOVE("movz.d $f0, $f2, $0");
233    TEST_MOVE("movz.d $f0, $f1, $0");
234    TEST_MOVE("movz.d $f1, $f2, $0");
235 }
236 
main()237 int main() {
238    int fr_prctl, fr_detected;
239 
240    test(&fr_prctl, &fr_detected);
241 
242    /* FP64 */
243    if (fr_prctl == 1) {
244 
245       /* Change mode to FP32 */
246       if (prctl(PR_SET_FP_MODE, 0) != 0) {
247          fatal_error("prctl(PR_SET_FP_MODE, 0) fails.");
248       }
249 
250       test(&fr_prctl, &fr_detected);
251 
252       /* Change back FP mode */
253       if (prctl(PR_SET_FP_MODE, 1) != 0) {
254          fatal_error("prctl(PR_SET_FP_MODE, 1) fails.");
255       }
256 
257       test(&fr_prctl, &fr_detected);
258    }
259 
260    return 0;
261 }
262 #else
main()263 int main() {
264    return 0;
265 }
266 #endif
267