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 130unsigned long source64 = 0x1234567890abcdefull; 131unsigned int source32 = 0x12345678u; 132 133/* Determine FP mode based on sdc1 behavior 134 returns 1 if FR = 1 mode is detected (assumes FRE = 0) */ 135static 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 152static void fatal_error(const char* msg) { 153 fprintf(stderr, "Error: %s\n", msg); 154 exit(1); 155} 156 157static 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 237int 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 263int main() { 264 return 0; 265} 266#endif 267