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